3D Interactive Book Component

3D book with CSS transforms and perspective.

CSS 3D Books That Don't Suck

Most 3D CSS components look kinda like they were made in 2010.

But this one? Actually clean. I built this for my x/ui library because I was tired of seeing janky book animations that made me want to close the tab.

Check out the full docs at ui.3x.gl/docs/book if you want to steal it.

Look at that smooth rotation. Zero jank.

Why Bother With 3D Books?

Because flat cards are kinda boring.

Seriously though, when you're showcasing content — portfolios, documentation, whatever — a little depth goes a long way. But most 3D CSS looks kinda like it was coded by someone who just discovered transform: rotateY().

This one actually feels like a book you'd want to pick up.

What I Built Instead

Multiple layers, proper perspective, and hover effects that don't make you nauseous:

tsx
interface BookProps {
  radius?: "sm" | "md" | "lg";
  size?: "sm" | "md" | "lg";  
  color?: keyof typeof colorMap;
  isStatic?: boolean;
  className?: string;
  children: React.ReactNode;
}

Basic props, nothing crazy. The isStatic prop is clutch — lets you decide if the book should rotate on hover or just stay tilted.

The Perspective Magic

tsx
<div className="group [perspective:800px] w-min">

800px perspective is the sweet spot. Too low and it looks weird, too high and you lose the effect. Trust me, I tried like 20 different values.

That Smooth Rotation

tsx
className={`[transform-style:preserve-3d] ${
  isStatic
    ? "[transform:rotateY(-30deg)]"
    : "[transform:rotateY(0deg)] group-hover:[transform:rotateY(-30deg)]"
}`}

30 degrees is perfect. Shows the spine without looking like the book is falling over.

The Layering Trick

Three layers make this work: front cover, spine, back cover. Each one positioned in 3D space like a real book.

Front Cover

tsx
<div
  style={{
    transform: "translateZ(25px)",
    boxShadow: "5px 5px 20px var(--shadowColor)",
  }}
>

Pushed forward 25px with a shadow that actually looks realistic.

The Spine (The Tricky Part)

tsx
<div
  style={{
    width: "48px",
    transform: `translateX(${sizeMap[size].spineTranslation}) rotateY(90deg)`,
    background: "linear-gradient(90deg, rgba(255,255,255,1) 50%, rgba(249,249,249,1) 50%)",
  }}
/>

Rotated 90 degrees and positioned just right. That gradient makes it look like actual book binding.

Back Cover

tsx
<div
  style={{
    transform: "translateZ(-25px)",
    boxShadow: "-10px 0 50px 10px var(--shadowColor)",
  }}
/>

Pushed back with a different shadow. The shadows sell the depth.

The Details That Matter

Spine Texture (Because I'm Obsessive)

css
background: linear-gradient(90deg, 
  hsla(0, 0%, 100%, 0), 
  hsla(0, 0%, 100%, 0) 12%, 
  hsla(0, 0%, 100%, .25) 29.25%, 
  hsla(0, 0%, 100%, 0) 50.5%, 
  hsla(0, 0%, 100%, 0) 75.25%, 
  hsla(0, 0%, 100%, .25) 91%, 
  hsla(0, 0%, 100%, 0)
)

Yeah, this gradient is ridiculous. But it mimics those little ridges on real book spines. Details matter.

Customization (Because Everyone Wants Different Sizes)

Size Variants

tsx
const sizeMap = {
  sm: { width: "180px", spineTranslation: "152px" },
  md: { width: "220px", spineTranslation: "192px" },
  lg: { width: "260px", spineTranslation: "232px" },
};

Those spine translation values? Calculated by hand because math is hard and I didn't want to do it in CSS.

22 Colors (Because Why Not)

tsx
const colorMap = {
  blue: { from: "from-blue-900", to: "to-blue-700" },
  red: { from: "from-red-900", to: "to-red-700" },
  // ... 20 more colors
};

All using Tailwind's color palette. The gradient from 900 to 700 gives it that nice depth without being too much.

How to Use It

tsx
<Book size="md" color="blue" radius="lg">
  <BookHeader>
    <Badge>React</Badge>
    <Badge>TypeScript</Badge>
  </BookHeader>
  <BookTitle>Component Design</BookTitle>
  <BookDescription>
    A comprehensive guide to building reusable UI components
  </BookDescription>
</Book>

Clean composition pattern. Header, title, description — mix and match however you want.

No weird prop drilling or configuration objects. Just drop in your content.

Performance Notes

CSS Custom Properties for Theming

css
[--shadowColor:#bbb] dark:[--shadowColor:#111]

Shadows switch with your theme automatically. No weird CSS-in-JS nonsense.

Hardware Acceleration

3D transforms trigger GPU acceleration by default. Smooth on potato laptops.

Wrap It Up

This is part of x/ui, my component library that doesn't suck.

Check out ui.3x.gl/docs/book for more examples and ways to break it.

The whole thing is TypeScript, accessible, and actually works on mobile. Revolutionary, I know.

Steal it. Make it better. Just don't make it uglier.

Command Palette

Search for a command to run...