Create an Interactive Folder Component in React
Build a skeuomorphic folder that opens and fans out its contents on click, making file groupings feel tangible.
Everyone knows what a folder does. That shared mental model is exactly what makes a skeuomorphic folder component so effective. No instructions needed. You click it and the papers come out.
The final result
What we are building
A clickable folder shape built entirely with CSS. On click, the folder flap opens and up to three paper cards fan out at different angles. The papers respond to mouse hover with a subtle magnetic pull effect while open.
Setting up
import React, { useState } from 'react';No dependencies. The folder shape, colors, and animations are pure CSS applied through Tailwind classes and inline styles.
Building the component
Color computation
The folder back needs to be slightly darker than the front to read as a shadow. We do this in JavaScript rather than CSS:
const darkenColor = (hex: string, percent: number): string => {
let color = hex.startsWith('#') ? hex.slice(1) : hex;
if (color.length === 3)
color = color.split('').map(c => c + c).join('');
const num = parseInt(color, 16);
let r = (num >> 16) & 0xff;
let g = (num >> 8) & 0xff;
let b = num & 0xff;
r = Math.max(0, Math.min(255, Math.floor(r * (1 - percent))));
g = Math.max(0, Math.min(255, Math.floor(g * (1 - percent))));
b = Math.max(0, Math.min(255, Math.floor(b * (1 - percent))));
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
};This gets called with darkenColor(color, 0.08) to produce folderBackColor.
The folder shape
The folder is built from a base rectangle (the back), a small tab protruding from the top-left, and two overlapping front flaps that skew in opposite directions. The skew is what makes it look like a flap opening:
<div className={`absolute z-30 w-full h-full origin-bottom transition-all duration-300 ease-in-out ${!open ? 'group-hover:[transform:skew(15deg)_scaleY(0.6)]' : ''}`}
style={{
backgroundColor: color,
borderRadius: '5px 10px 10px 10px',
...(open && { transform: 'skew(15deg) scaleY(0.6)' }),
}}
/>
<div className={`absolute z-30 w-full h-full origin-bottom transition-all duration-300 ease-in-out ${!open ? 'group-hover:[transform:skew(-15deg)_scaleY(0.6)]' : ''}`}
style={{
backgroundColor: color,
borderRadius: '5px 10px 10px 10px',
...(open && { transform: 'skew(-15deg) scaleY(0.6)' }),
}}
/>The two flaps skew in opposite directions (15deg and -15deg), creating a split that reads as an opening flap.
Paper fanning
Each paper gets a preset transform when open. The offsets are hardcoded for three items:
const getOpenTransform = (index: number) => {
if (index === 0) return 'translate(-120%, -70%) rotate(-15deg)';
if (index === 1) return 'translate(10%, -70%) rotate(15deg)';
if (index === 2) return 'translate(-50%, -100%) rotate(5deg)';
return '';
};Mouse magnetism on open papers
When the folder is open, hovering over a paper makes it drift slightly toward the cursor. We track mouse offset from the paper center and multiply by 0.15 to keep the movement subtle:
const handlePaperMouseMove = (e: React.MouseEvent<HTMLDivElement>, index: number) => {
if (!open) return;
const rect = e.currentTarget.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const offsetX = (e.clientX - centerX) * 0.15;
const offsetY = (e.clientY - centerY) * 0.15;
setPaperOffsets(prev => {
const n = [...prev];
n[index] = { x: offsetX, y: offsetY };
return n;
});
};How to use it
<Folder
color="#5227FF"
size={1}
items={[
<img src="/thumb1.jpg" className="w-full h-full object-cover rounded-[10px]" />,
<img src="/thumb2.jpg" className="w-full h-full object-cover rounded-[10px]" />,
<img src="/thumb3.jpg" className="w-full h-full object-cover rounded-[10px]" />,
]}
/>| Prop | Default | Description |
|------|---------|-------------|
| color | #5227FF | Folder accent color |
| size | 1 | Scale multiplier for the entire component |
| items | [] | Up to 3 React nodes to show as papers |
Key takeaways
- The folder flap effect uses two overlapping
divelements that skew in opposite directions. This is simpler than trying to animate a single element and reads clearly at any size. origin-bottomon the flap divs makes the skew animate from the bottom edge, which is exactly where a real folder hinge would be.- The paper magnetism resets to zero on
mouseleave, so papers always return to their fanned position rather than staying off-center.