React 3D components

Depth, perspective and real rotation, most of it in plain CSS rather than a 3D engine. Copy any one into your project and it runs without a renderer.

Built with the stack you already ship

React
Next.js
TypeScript
Tailwind CSS
Framer Motion
Vite
Astro
React
Next.js
TypeScript
Tailwind CSS
Framer Motion
Vite
Astro

3D components built with CSS

These use transform, perspective and preserve-3d only. No renderer, no shader compilation, and no extra bytes beyond the component itself.

3D components built with WebGL

These load a renderer and compile shaders before their first frame. Worth the weight when the effect is the point, and worth checking on a mid range phone.

CSS 3D or WebGL, and how to tell which you need

Most things people call a 3D component in React are not running a 3D engine at all. A card that tilts toward the cursor, a book that opens, a stack that fans out: all of that is CSS transforms with a perspective value set on the parent and transform-style set to preserve-3d on the child. The browser composites it on the GPU, it costs nothing to load, and it degrades to a flat layout if transforms are unsupported. Reach for this first, because it covers more cases than people expect.

You need actual WebGL when the surface itself has to be computed per pixel. A globe with an atmosphere, a fluid orb, refraction that bends whatever sits behind the element: none of those can be expressed as a transform on a rectangle, because they depend on lighting and distortion across the whole surface. That is the line. If you can describe the effect as moving and rotating flat panels, CSS will do it. If you have to describe it as light behaving a certain way, you need a renderer.

The cost difference is not subtle. A CSS 3D component ships as one file and animates the moment the stylesheet parses. A WebGL component pulls in a renderer, compiles its shaders, and only then paints its first frame, which on a mid range Android phone is a visible pause. That pause is fine three screens down the page and a real problem if the component is the largest thing above the fold, where it becomes the element Google times for Largest Contentful Paint.

Perspective value is the setting that most often makes a CSS 3D effect look wrong. It is the distance from the viewer to the z equals zero plane, so a small number like 400px gives a strong, almost fisheye distortion, and a large number like 2000px flattens the effect until it barely reads. Set it on the container rather than the transformed element, otherwise each child gets its own vanishing point and the group stops looking like one scene.

Whatever you pick, check it against reduced motion. A component that rotates continuously is exactly the kind of thing that triggers motion sickness, and the browser already tells you when someone has asked for less of it. Everything here respects the prefers-reduced-motion media query by settling into a static state rather than disabling itself, so the component still communicates what it is without moving.

Frequently asked questions

Usually not. Card tilts, flipping panels, opening books, perspective grids and device mockups are all CSS transforms with perspective and preserve-3d, which ship no extra JavaScript at all. Three.js earns its weight when the effect depends on per pixel lighting or distortion, such as a globe with an atmosphere or real refraction. Of the 3D components in this library, most are pure CSS.
Yes. Transform and opacity are composited on the GPU and skip layout and paint entirely, which is why a CSS 3D card stack holds 60fps while animating width or top would not. This is also why the components here animate transform rather than position properties, even where the visual result would look similar.
The CSS based ones will not, because they add no runtime dependency and animate on the compositor. The WebGL ones will, because a renderer has to load and shaders have to compile before the first frame appears. If a WebGL component sits above the fold, put a static image behind it as a poster or move it below the fold so it is not the element that gets timed.
The CSS 3D components work everywhere transforms are supported, which is every current browser including iOS Safari. The WebGL ones need a working WebGL context, which is close to universal now but degrades to a static fallback where it is missing or where the device reports low power. Test the WebGL ones on a real mid range phone rather than a desktop throttled in DevTools, because shader compilation time is the part that does not simulate well.
Every component here reads the prefers-reduced-motion media query and settles into a composed static state instead of removing itself. That matters because continuous rotation and parallax are common motion sickness triggers. If you build your own, wrap the animation rather than the element, so the layout stays identical and only the movement stops.

Where to go next