July 12, 2026

What makes a div read as a folder?

JavaScriptCSSSVGOpen Source
What makes a div read as a folder?

The folder gallery on my homepage is about 15 KB of vanilla JavaScript and one SVG path. Almost none of the build time went into the 3D math. It went into a much more annoying problem: the thing kept rendering correctly and still not looking like a folder.

I extracted the component into a small library called flipfolio last week, and packaging it forced me to name what actually carries the illusion. It came down to three things: the silhouette, the front panel, and the depth math. There is also the behind-the-scenes accessibility of it all.

Where does the folder-ness live?

In the outline, it turns out. The whole silhouette - tab, shoulders, body - is a single SVG path in a 480 by 342 viewBox, stretched to fit with preserveAspectRatio set to none. Swap the path and you swap the identity: a right-side tab, a tabless tray, a sharper cut, all the same engine with one attribute changed.

But a path alone is not a folder. It is a colored blob with a tab :)

What separates a folder from a colored rectangle?

A gap. A real folder is two pieces of material with space between them, so the component is built that way: the SVG path is the back, and a separate front panel covers the lower three quarters. Contents sit between the two planes and slide out of the mouth on hover.

The front panel pays for itself twice. The active card's front is translucent with a backdrop blur, so whatever is inside shows through as a frosted hint, and the four cards behind it stay fully opaque. That split is partly a design call and partly survival: backdrop-filter does not stack politely, and five blurred layers running at once will spin up a laptop fan.

Color works the same way - one input, three surfaces. You pass a single hex per folder and the engine derives the rest: the back sits 30 points darker, the frosted front 40 lighter at 55 percent alpha, the solid front 35 lighter. You configure a color; you get a skin.

How much math does depth actually need?

Waaaay less than I thought. Each card behind the active one gets a transform computed from its distance: position 1 sits 28 pixels higher and 25 back, position 2 sits 60 higher and 62 back. Both terms carry a squared component, so the pile compresses toward the rear the way paper actually stacks. Add a 3 degree tilt per step and a shrinking scale, and 8 folders read as something you could pick up. I can't claim the squared falloff is perceptually correct - it is just the curve that visually felt good enough.

Getting photo mode setup was the most time-consuming part of this. I wrapped an image around the entire folder, tab included, then added a highlight along the fold... and it looked terrible. Photos now print on the front panel only, the back and tab keep their color.

What about the parts you cannot see?

To a screen reader the gallery is a listbox: real options, roving tabindex, arrow keys, and position announcements through a live region. Wheel and touch navigation both work. Under prefers-reduced-motion the tilt drops and transitions collapse to a frame.

Tools and limits

The core is dependency-free vanilla JavaScript, about 15 KB before compression, with 40 tests across it and its wrappers. React and Vue get thin adapters. There is a web component if you would rather skip frameworks entirely. All 3 layouts share one normalized transform function.

Everything renders on the client, so there is no SSR of the layout itself. And every folder is a live 3D layer, which puts the sweet spot at a dozen items, not hundreds. I built it for things you curate. It's a portfolio.

Demo: kirthi.studio/demos/flipfolio Code: github.com/kirthi-b/flipfolio