3D Flexbox Layouts with React Three Flex

The author
Stephen Castle4 years ago

React Three Flex is a new library which can layout 3D elements in a React Three Fiber scene using Yoga (Facebook's Flex Box implementation). There are some amazing demo's that show off the creative power of the library on GitHub so if you're looking for something more advanced that's a great place to start. Here is one of them for an example of this libraries power.

In the below example we will strive to strip away all of the extra features going on in an example like the one above and just implement a bare minimum usage of the library. Our goal here is to reduce the complexity enough to get a feel for the basic layout features before moving on to a more advanced usage.

Start a new project with React Three Fiber, React Three Flex, and Drei

Make sure you have Node installed and run the following commands. First we need to bootstrap a new React app, then install the dependencies. We need three.js, react-three-fiber, react-three-flex, and drei.

npx create-react-app 3d-flex-demo
cd 3d-flex-demo
npm install -g three react-three-fiber react-three-flex drei

Set up some basic CSS and Import react-three-fiber react-three-flex and set up a scene tree

This css will ensure your 3D viewport takes up the entire Browser viewport.

/*styles.css*/
* {
  box-sizing: border-box;
}

html,
body,
#root {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  background: #000000;
  font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, helvetica
      neue, helvetica, ubuntu, roboto, noto, segoe ui, arial, sans-serif;
}

The rest of the tutorial will be editing the App.js file exclusively.

import React from "react";
import * as THREE from "three";

import { Canvas } from "react-three-fiber";

import { Flex, Box } from "react-three-flex";
import "./styles.css";

export default function App() {
  return (
    <Canvas>
      <Flex>
        <Box></Box>
      </Flex>
    </Canvas>
  );
}

React Three Flex works primarily by nesting Box components inside of a top level Flex component. You can also nest additional Box components inside of a parent Box component. The library will use these components, combined with their props to figure out where to place any objects contained inside the Box.

In this code we now have a working default Flexbox layout with no content inside of it. You won't see anything until the next step where we will add some content to render inside of a box.

Add a Sphere from Drei to the Flex Layout

We can use the great React Three helper library Drei and get some basic geometry to use in the demo. If you haven't used Drei before check it out for some really handy tools that can save you a lot of boilerplate when working with React Three Fiber.

import React from "react";

import { Canvas } from "react-three-fiber";

import { Flex, Box } from "react-three-flex";
import { Sphere } from "drei";
import "./styles.css";

export default function App() {
  return (
    <Canvas>
      <directionalLight intensity={0.5} />
      <Flex>
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="white" />
          </Sphere>
        </Box>
      </Flex>
    </Canvas>
  );
}

In this step we added a Sphere components from drei, set the size to 1, with a meshLambertMaterial as a child. We also added a light just to create some shading and prove to ourselves these are 3d objects. You should see a gray sphere in the middle of the viewport now. So far not much is happening, in the next step we will add 2 more Spheres each in their own Box component and see how React Three Flex handles it.

Adding More Spheres to the Layout

import React from "react";

import { Canvas } from "react-three-fiber";

import { Flex, Box } from "react-three-flex";
import { Sphere } from "drei";
import "./styles.css";

export default function App() {
  return (
    <Canvas>
      <directionalLight intensity={0.5} />
      <Flex>
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="red" />
          </Sphere>
        </Box>
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="yellow" />
          </Sphere>
        </Box>
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="green" />
          </Sphere>
        </Box>
      </Flex>
    </Canvas>
  );
}

Ok now things are starting to get a little interesting. There are now 3 spheres lined up in a straight line going down and off the screen. So React Three Flex is obviously doing something and lining up those Spheres. But how can we place them where we really want them? First let's just arrange them in a horizontal row instead of straight up and down, we can also zoom out the camera a bit for a better view.

Using Flex Properties to change the Layout Behavior

import React from "react";

import { Canvas } from "react-three-fiber";

import { Flex, Box } from "react-three-flex";
import { Sphere } from "drei";
import "./styles.css";

export default function App() {
  return (
    //highlight-start
    <Canvas camera={{ position: [0, 0, 10] }}>
      //highlight-end
      <directionalLight intensity={0.5} />
      //highlight-start
      <Flex size={[300, 300, 300]} flexDirection="row">
        //highlight-end
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="red" />
          </Sphere>
        </Box>
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="yellow" />
          </Sphere>
        </Box>
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="green" />
          </Sphere>
        </Box>
      </Flex>
    </Canvas>
  );
}

Now the spheres should line up horizontally, first we defined a size on the Flex component. The size prop takes a vector representing the x, y, z size. React Three Flex needs this to know the container size you want to constrain your content to. Second we set the prop flexDirection to "row". If you are familiar with css flex box this will look very familiar to you. The props of the Flex component mirror the Flexbox properties used in CSS.

Using Flex Wrap and Flex Basis to Adjust the Positioning of Boxs in the Flex

Let's use some more flex box properties to make a third layout, where two spheres are in the first row, and the third sphere is dropped down to the second row.

import React from "react";

import { Canvas } from "react-three-fiber";

import { Flex, Box } from "react-three-flex";
import { Sphere } from "drei";
import "./styles.css";

export default function App() {
  return (
    <Canvas camera={{ position: [0, 0, 10] }}>
      <directionalLight intensity={0.5} />
      //highlight-start
      <Flex size={[300, 300, 300]} flexDirection="row" flexWrap="wrap">
        //highlight-end
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="red" />
          </Sphere>
        </Box>
        <Box>
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="yellow" />
          </Sphere>
        </Box>
        //highlight-start
        <Box flexBasis="100%">
          //highlight-end
          <Sphere args={[1, 16, 16]}>
            <meshLambertMaterial attach="material" color="green" />
          </Sphere>
        </Box>
      </Flex>
    </Canvas>
  );
}

Using two new props, flexWrap on the Flex component, and flexBasis on the third Box component we were able to layout the third sphere in a new row. By setting flexBasis to 100% we told the flex layout engine to reserve 100% of the width for that Box, and since it couldn't fit that on the first row, and because we enabled flexWrap by setting it to wrap, react-three-flex moved it down to its own row.

If you've followed all of the steps above you should have a very basic set of 3 spheres that look just like this. I hope this has been helpful to absolute newcomers to react-three-flex. In a future tutorial we will expand on these basics and try building something a little more useful.

If you are ready now to explore a slightly more complicated, but still simplified demo of React Three Flex, try poking around in this sandbox which adds in the rather useful feature of being able to scroll the 3d Elements in the flex layout.