{"id":13469686,"url":"https://github.com/pmndrs/react-three-flex","last_synced_at":"2025-04-13T08:59:45.582Z","repository":{"id":38826363,"uuid":"288521171","full_name":"pmndrs/react-three-flex","owner":"pmndrs","description":"💪📦  Flexbox for react-three-fiber","archived":false,"fork":false,"pushed_at":"2022-12-06T08:37:19.000Z","size":6504,"stargazers_count":1700,"open_issues_count":18,"forks_count":42,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-04-12T19:25:07.091Z","etag":null,"topics":["3d","flex","flexbox","r3f","react","react-three-fiber","three","yoga","yoga-layout"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pmndrs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-18T17:31:26.000Z","updated_at":"2025-04-07T20:31:23.000Z","dependencies_parsed_at":"2022-07-11T19:54:32.343Z","dependency_job_id":null,"html_url":"https://github.com/pmndrs/react-three-flex","commit_stats":null,"previous_names":["react-spring/react-three-flex"],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmndrs%2Freact-three-flex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmndrs%2Freact-three-flex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmndrs%2Freact-three-flex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmndrs%2Freact-three-flex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pmndrs","download_url":"https://codeload.github.com/pmndrs/react-three-flex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248688551,"owners_count":21145765,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d","flex","flexbox","r3f","react","react-three-fiber","three","yoga","yoga-layout"],"created_at":"2024-07-31T15:01:50.763Z","updated_at":"2025-04-13T08:59:45.556Z","avatar_url":"https://github.com/pmndrs.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","2D GUI","3D","Uncategorized"],"sub_categories":["Layout","Uncategorized"],"readme":"# @react-three/flex\n\n[![Build Status](https://img.shields.io/github/workflow/status/pmndrs/react-three-flex/Release?style=flat\u0026colorA=000000\u0026colorB=000000)](https://github.com/pmndrs/react-three-flex/releases)\n[![Version](https://img.shields.io/npm/v/@react-three/flex?style=flat\u0026colorA=000000\u0026colorB=000000)](https://www.npmjs.com/package/@react-three/flex)\n[![Downloads](https://img.shields.io/npm/dt/@react-three/flex.svg?style=flat\u0026colorA=000000\u0026colorB=000000)](https://www.npmjs.com/package/@react-three/flex)\n[![Discord Shield](https://img.shields.io/discord/740090768164651008?style=flat\u0026colorA=000000\u0026colorB=000000\u0026label=discord\u0026logo=discord\u0026logoColor=ffffff)](https://discord.gg/ZZjjNvJ)\n\nPlacing content in THREE.js is hard. **`@react-three/flex`** brings the webs flexbox spec to [react-three-fiber](https://github.com/pmndrs/react-three-fiber).\nIt is based on [Yoga](https://github.com/facebook/yoga), Facebook's open source layout engine for react-native.\n\n```bash\nnpm install @react-three/flex\n```\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://codesandbox.io/embed/7psew\"\u003e\u003cimg width=\"274\" src=\"https://i.imgur.com/FOqC6Ml.gif\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://codesandbox.io/embed/gallant-elbakyan-lvwmj\"\u003e\u003cimg width=\"274\" src=\"https://i.imgur.com/PrQX2uI.gif\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://codesandbox.io/embed/r3flex-kbs4y\"\u003e\u003cimg width=\"274\" src=\"https://i.imgur.com/fykLiRl.gif\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"middle\"\u003e\n  \u003ci\u003eThese demos are real, you can click them! They contain the full code, too.\u003c/i\u003e\n\u003c/p\u003e\n\n## Table of contents\n\n- [Usage](#usage)\n  - [Anchors](#anchors)\n  - [Stretching](#stretching)\n  - [Invalidation and Reflow](#invalidation-and-reflow)\n  - [Sizing](#sizing)\n  - [Axis Orientation](#axis-orientation)\n  - [Margin and Padding](#margin-and-padding)\n  - [Nesting](#nesting)\n  - [Measuring the Container](#measuring-the-container)\n- [API](#api)\n  - [Flexbox props](#flexbox-props)\n\n## Usage\n\nSimply create layouts by wrapping your 3D objects in different `\u003cBox /\u003e` instances inside a `\u003cFlex /\u003e` container. This way they will be automatically placed in the 3D space following the flexbox specification just like in the DOM.\n\n```jsx\nimport { Flex, Box } from '@react-three/flex'\n\nconst Layout = () =\u003e (\n  \u003cFlex justifyContent=\"center\" alignItems=\"center\"\u003e\n    \u003cBox centerAnchor\u003e\n      \u003cmesh geometry={box} /\u003e\n    \u003c/Box\u003e\n    \u003cBox centerAnchor flexGrow={1}\u003e\n      \u003cmesh geometry={torus} /\u003e\n    \u003c/Box\u003e\n  \u003c/Flex\u003e\n)\n```\n\nYou can tweak the container and the boxes using standard CSS flex properties, like `flexDirection` or `justifyContent` for the container and `flexGrow` for the boxes. There are also _shorthands_, like `align` and `justify`. See the props docs below for more info.\n\n### Anchors\n\nWhen positioning items, `react-three-flex` needs to know where the object anchor is: Yoga Layout expects the object position to be relative to the upper left corner, which is the same as the DOM expects.\n\nMost THREE.js geometries, though, are positioned relative to the object center. To tell `react-three-flex` that your `\u003cBox /\u003e` positioning is relative to the center you need to set the `centerAnchor` prop to true.\n\n```jsx\n\u003cBox centerAnchor\u003e\n  \u003cmesh geometry={sphere} /\u003e\n\u003c/Box\u003e\n```\n\nIf you nest `\u003cBox /\u003e` elements, though, you need to set it to false. See [Nesting](#nesting).\n\n![Anchors](./docs/anchors.png)\n\n### Stretching\n\nBy default `@react-three/flex` controls elements position only. In some cases you may want to control element sizing too. Since `@react-three/flex` has no information about how the inner content size works, you need to set your content size manually. To do so `@react-three/flex` provides you the container size in two ways:\n\n- Using a **children render function**:\n\n```jsx\n\u003cFlex\u003e\n  \u003cBox width=\"auto\" height=\"auto\" flexGrow={1} centerAnchor\u003e\n    {(width, height) =\u003e \u003cPlane args={[width, height]} /\u003e}\n  \u003c/Box\u003e\n\u003c/Flex\u003e\n```\n\n- Using a **hook**:\n\n```jsx\nfunction Inner() {\n  const [width, height] = useFlexSize()\n  return \u003cPlane args={[width, height]} /\u003e\n}\n\nfunction Outer() {\n  return (\n    \u003cFlex\u003e\n      \u003cBox width=\"auto\" height=\"auto\" flexGrow={1} centerAnchor\u003e\n        \u003cInner /\u003e\n```\n\nRemember that the `useFlexSize` hook works **ONLY** if your `\u003cBox/\u003e` is outside the component.\n\n### Invalidation and Reflow\n\nWhile the DOM's Flexbox has full control over all the changes of the tree, `@react-three/flex` runs on React, hence it has no way to know if a children size or shape has changed. For performance reasons Flex layout calculation _does not run every frame_, and it has to be triggered manually in some cases.\n\n**What will trigger a reflow:**\n\n- `\u003cFlexbox/\u003e` props changes (alignItems, size, ...)\n- `\u003cBox/\u003e` props changes (flexGrow, margin, ...)\n- `\u003cFlexbox/\u003e` and `\u003cBox/\u003e` rerenders with children differences\n\n```jsx\nfunction AnimatedBox() {\n  // Since \u003cBox/\u003e is inside the component, setting the state will rerender it, thus causing a reflow.\n  // ⚠️ If \u003cBox/\u003e were outside this component, this would NOT cause a reflow!\n  const [state, setState] = useState(true)\n  useInterval(() =\u003e setState((s) =\u003e !s), 1000)\n  return (\n    \u003cBox centerAnchor\u003e\n      \u003cmesh\u003e\n        \u003cboxBufferGeometry attach=\"geometry\" args={[state ? 10 : 30, 10, 10]} /\u003e\n```\n\n**This will NOT cause a reflow!**\n\n```jsx\nfunction AnimatedBox() {\n  // ⚠️ Setting state does not rerender \u003cBox/\u003e since it's in the parent\n  // ‼️ No Reflow!!\n  const [state, setState] = useState(true)\n  useInterval(() =\u003e setState((s) =\u003e !s), 1000)\n  return (\n    \u003cmesh scale={[state ? 1 : 3, 1, 1]}\u003e\n      \u003cboxBufferGeometry attach=\"geometry\" /\u003e\n    \u003c/mesh\u003e\n  )\n}\n\nfunction Layout() {\n  return (\n    \u003cFlex\u003e\n      \u003cBox centerAnchor\u003e\n        \u003cAnimatedBox /\u003e\n```\n\nFor every other case (setting size with the `useFrame` hook, performing `react-spring` animation, or `\u003cBox/\u003e` are not rerendered) you'll need to **manually cause a reflow**, using the `useReflow()` hook. Reflows requests are batched every frame so you can call it from hundreds of components without performance issues.\n\n**Animation with useFrame():**\n\n```jsx\nfunction AnimatedBox() {\n  const ref = useRef()\n  const reflow = useReflow()\n  useFrame(({ clock }) =\u003e {\n    ref.current.scale.x = 1 + Math.sin(clock.getElapsed())\n    reflow()\n  })\n  return (\n    \u003cBox centerAnchor\u003e\n      \u003cmesh ref={ref}\u003e\n```\n\n**`\u003cBox/\u003e` outside of component:**\n\n```jsx\nfunction AnimatedBox() {\n  const [state, setState] = useState(true)\n  useInterval(() =\u003e setState((s) =\u003e !s), 1000)\n  const reflow = useReflow()\n  useEffect(reflow, [state])\n  return (\n    \u003cmesh ref={ref} scale={[state ? 1 : 3, 1, 1]}\u003e\n```\n\n### Sizing\n\n`@react-three/flex` differs from DOM Flexbox in that it relies on a parent container for the root flex. It is required to specify its dimensions using `size` prop for wrapping and to be responsive.\n\n```jsx\n\u003cFlex flexDirection=\"row\" flexWrap=\"wrap\" size={[300, 200, 0]}\u003e\n  {/* ... */}\n\u003c/Flex\u003e\n```\n\n**⚠️ WATCH OUT!** Yoga flexbox engine uses whole integer numbers to perform layout calculation to preserve precision - `@react-three/flex` multiplies every element size and flex prop by the `scaleFactor` of the root flex container. By default it's `100`, and works well for small scenes. If you use a different scene scale, make sure to tweak it accordingly.\n\n![Bounds](./docs/bounds.png)\n\n### Axis Orientation\n\nAnother important difference with DOM Flexbox is that you have to specify the plane of the container in 3D. The elements will be positioned in the 2D plane given by the two axes, using width and height calculated along the two axes.\n\nThe 2D flex container width and height will be calculated by looking at the `size` prop with respect of the chosen axes (`100` for `x` and `200` for `y` in this example).\n\nThe default plane is `xy`, the other possibilites are `yz` and `xz`.\n\n```jsx\n\u003cFlex plane=\"xy\" size={[100, 200, 0]}\u003e\n  {/* ... */}\n\u003c/Flex\u003e\n```\n\n![Axes Orientation](./docs/axes_orientation.png)\n\n### Margin and Padding\n\nFor every `\u003cFlex /\u003e` and `\u003cBox /\u003e` component you can specify the margin and padding like in DOM elements.\n\n```jsx\n\u003cFlex flexDirection=\"row\" size={[300, 200, 0]} padding={30} margin={5}\u003e\n  \u003cBox padding={5} marginTop={5} centerAnchor\u003e\n    \u003cmesh geometry={sphere} /\u003e\n  \u003c/Box\u003e\n\u003c/Flex\u003e\n```\n\n![Margin](./docs/margin.png)\n\n### Nesting\n\nSince a `\u003cFlex /\u003e` component works the same way as a DOM one, you can easily make complex layouts by nesting flex containers.\n\n```jsx\n\u003cFlex flexDirection=\"row\" flexWrap=\"wrap\" size={[50, 0, 0]}\u003e\n  \u003cBox centerAnchor\u003e\n    \u003cmesh geometry={sphere} /\u003e\n  \u003c/Box\u003e\n  \u003cBox flexDirection=\"column\" flexWrap=\"no-wrap\"\u003e\n    \u003cBox centerAnchor\u003e\n      \u003cmesh geometry={sphere} /\u003e\n    \u003c/Box\u003e\n    \u003cBox centerAnchor\u003e\n      \u003cmesh geometry={box} /\u003e\n    \u003c/Box\u003e\n  \u003c/Box\u003e\n\u003c/Flex\u003e\n```\n\n### Measuring the container\n\nWhen building responsive layouts you might need to synchronize the size of the 3D Flex container with the DOM, for example to synchronize scroll position or to modify the height of a scroll container.\nTo make it easier, you can use the `onReflow` prop on the root `\u003cFlex\u003e` component that will be called every time the flex layout is recalculated - e.g. when any content changes.\n\n```jsx\n\u003cFlex onReflow={(totalWidth, totalHeight) =\u003e ...}\u003e\n {/* ... */}\n\u003c/Flex\u003e\n```\n\n## API\n\nYou can find a full list of props [here](https://github.com/pmndrs/react-three-flex/blob/master/src/props.ts).\n\n```jsx\n\u003cFlex\n  size={[1, 1, 1]} // Total size of the flex container, see above\n  position={[0, 0, 0]} // Default - position for the flex container in the scene\n  direction=\"ltr\" // Default - right to left or right to left\n  plane=\"xy\" // Default - plane axes, see above\n  scaleFactor={100} // Default - integer scale factor, see above (Sizing)\n  onReflow={fn} // Called everytime the layout is recalculated\n  {...R3FlexProps} // Standard Flexbox props, described below\n\u003e\n  \u003cBox\u003e{/* ... */}\u003c/Box\u003e\n\u003c/Flex\u003e\n```\n\n```jsx\n\u003cBox\n  centerAnchor // If the inner content position is relative to its center, see above (Anchors)\n  {...R3FlexProps} // Standard Flexbox props, described below\n\u003e\n  \u003cmesh geometry={box} /\u003e\n\u003c/Box\u003e\n```\n\nOr you can pass a **function as children**:\n\n```jsx\n\u003cBox\u003e{(width, height) =\u003e \u003cModel width={width} height={height} /\u003e}\u003c/Box\u003e\n```\n\n### Flexbox props\n\nBoth `\u003cFlex/\u003e` and `\u003cBox /\u003e` components share the same Flexbox props API from Yoga. The library also provides string and number inputs for convenience and shorthands.\n\nExample:\n\n```jsx\n// Flex with padding top set to 10, alignItems to 'center', justifyContent to 'space-around' and flexWrap to 'wrap'\n\u003cFlex pt={10} align=\"center\" justify=\"space-around\" wrap=\"wrap\"\u003e\n  {/* ... */}\n\u003c/Flex\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmndrs%2Freact-three-flex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpmndrs%2Freact-three-flex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmndrs%2Freact-three-flex/lists"}