Oblivion
Oblivion
Docs
Go back
Component by
OV
Oblivion
Taxes 2026
📑
Taxes 2026 Data

Confidential documents stored securely in this manila folder representation.

Invoices
Receipts
Contracts
TSX
manila-folder-stack
"use client"

import React, { useState } from "react"
import { motion } from "framer-motion"
import { cn } from "@/lib/utils"

export const componentMeta = {
  name: "Manila Folder Stack",
  description: "A skeuomorphic, delightfully tactile stacked folder layout. Clicking a folder smoothly brings it to the front.",
  props: {
    className: { type: "string", description: "Additional CSS classes", default: '""' }
  }
}

const FOLDERS = [
  { id: "taxes", title: "Taxes 2026", color: "bg-[#F4E6B4]", tabColor: "bg-[#E6D491]", text: "text-yellow-900" },
  { id: "invoices", title: "Invoices", color: "bg-[#E2F0CB]", tabColor: "bg-[#C4DC9C]", text: "text-green-900" },
  { id: "receipts", title: "Receipts", color: "bg-[#FFDAC1]", tabColor: "bg-[#E7B896]", text: "text-orange-900" },
  { id: "contracts", title: "Contracts", color: "bg-[#E0E0E0]", tabColor: "bg-[#C9C9C9]", text: "text-neutral-800" },
]

export default function ManilaFolderStack({ className }: { className?: string }) {
  const [activeFolder, setActiveFolder] = useState<string>("taxes")

  return (
    <div className={cn("w-full max-w-lg h-[500px] flex items-center justify-center relative p-8", className)}>
      {FOLDERS.map((folder, index) => {
        const isActive = activeFolder === folder.id
        // When pushed to the back, folders visually stack upwards.
        const yOffset = isActive ? 0 : -30 * index
        const scale = isActive ? 1 : 1 - (index * 0.05)
        const zIndex = isActive ? 40 : FOLDERS.length - index

        return (
          <motion.div
            key={folder.id}
            layout
            onClick={() => setActiveFolder(folder.id)}
            initial={false}
            animate={{
              y: yOffset,
              scale: scale,
              zIndex: zIndex,
            }}
            transition={{ type: "spring", stiffness: 250, damping: 25 }}
            className="absolute bottom-12 w-full max-w-sm h-[320px] flex flex-col cursor-pointer transition-shadow"
            style={{ transformOrigin: "bottom center" }}
            whileHover={!isActive ? { y: yOffset - 10 } : {}}
          >
            {/* The Tab */}
            <div className="flex px-4" style={{ zIndex: 10 }}>
               <div 
                 className={cn(
                   "px-5 py-2.5 rounded-t-xl font-bold tracking-wide shadow-[-2px_0px_5px_rgba(0,0,0,0.05)]", 
                   folder.tabColor, folder.text
                 )} 
                 style={{ marginLeft: `${index * 15}%` }}
               >
                 {folder.title}
               </div>
            </div>

            {/* The Folder Body */}
            <div 
              className={cn(
                "flex-1 rounded-2xl rounded-tl-none p-6 shadow-[0_10px_30px_rgba(0,0,0,0.15),inset_0_2px_4px_rgba(255,255,255,0.8)] border-t border-white/40", 
                folder.color
              )}
            >
                {isActive && (
                   <motion.div 
                     initial={{ opacity: 0, y: 10 }} 
                     animate={{ opacity: 1, y: 0 }} 
                     transition={{ delay: 0.15, duration: 0.3 }} 
                     className="w-full h-full bg-white/40 backdrop-blur-sm border border-white/50 border-dashed rounded-xl flex flex-col items-center justify-center p-4 gap-3 shadow-inner text-center"
                   >
                     <div className="w-12 h-12 rounded-full bg-white/60 flex items-center justify-center shadow-sm">
                       <span className="text-xl font-bold opacity-60">📑</span>
                     </div>
                     <span className={cn("font-medium uppercase tracking-widest text-sm opacity-80", folder.text)}>
                       {folder.title} Data
                     </span>
                     <p className="text-xs opacity-60 font-medium px-4">
                       Confidential documents stored securely in this manila folder representation.
                     </p>
                   </motion.div>
                )}
            </div>
          </motion.div>
        )
      })}
    </div>
  )
}
Save to favoritesCopy to Figma
React

Manila Folder Stack

A skeuomorphic, delightfully tactile stacked folder layout. Clicking a folder smoothly brings it to the front.

Installation

$ npx @cosmoo/oblivion add manila-folder-stack
Dependenciesnpm install framer-motion

Usage Example

tsx
import ManilaFolderStack from "@/components/oblivion/manila-folder-stack"

export default function Demo() {
  return (
    <div className="p-10 flex justify-center">
      <ManilaFolderStack />
    </div>
  )
}