--- name: expandable-card description: Creates expandable/collapsible cards using CSS grid-rows animation with smooth transitions. Use when building accordions, expandable panels, collapsible sections, or show/hide card content. --- # Expandable Card Pattern Build smooth expand/collapse animations using CSS grid-rows, avoiding height:auto animation issues. ## Why grid-rows? Traditional height animation requires explicit pixel values. The `grid-rows` technique allows smooth animation to/from `auto` height: - `grid-rows-[0fr]` + `overflow-hidden` = collapsed (0 height) - `grid-rows-[1fr]` = expanded (natural height) ## Core Implementation ```tsx "use client"; import { useState } from "react"; import { ChevronDown } from "lucide-react"; function ExpandableCard() { const [expanded, setExpanded] = useState(true); return (
{/* Header - clickable toggle */}
setExpanded(!expanded)} > Card Title
{/* Content - animated container */}
{/* Your content here */}

Expandable content goes here.

); } ``` ## Key Elements ### 1. State Management ```tsx const [expanded, setExpanded] = useState(true); // Start expanded // or const [expanded, setExpanded] = useState(false); // Start collapsed ``` ### 2. Header Click Handler ```tsx
setExpanded(!expanded)} > ``` ### 3. ChevronDown Rotation ```tsx ``` ### 4. Grid Container Animation ```tsx
{/* Content wrapper - REQUIRED for animation */}
``` ## Timing Recommendations | Duration | Use Case | |----------|----------| | `duration-150` | Small cards, quick feedback | | `duration-200` | Chevron rotation | | `duration-300` | Content expansion (recommended) | | `duration-500` | Large content areas | ## Shadow Transition (Optional) Add shadow that changes with state: ```tsx
``` ## Accessibility Considerations ```tsx
setExpanded(!expanded)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setExpanded(!expanded); } }} > ``` ## Common Variations ### Multiple Cards (Accordion) ```tsx const [expandedId, setExpandedId] = useState("first"); // Toggle logic onClick={() => setExpandedId(expandedId === id ? null : id)} ``` ### Nested Content Protection Prevent clicks on interactive content from toggling: ```tsx e.stopPropagation()} > ``` **Important**: Always add `stopPropagation` to: - Links (``) - Buttons that perform actions other than toggling - Form inputs - Any interactive element that shouldn't trigger expand/collapse ```tsx // Full example with multiple interactive elements
e.stopPropagation()} className="text-blue-500 hover:underline" > External link
``` ## Checklist - [ ] `overflow-hidden` on inner wrapper (required for animation) - [ ] `transition-all` on grid container - [ ] ChevronDown has `transition-transform` - [ ] Header has `cursor-pointer` and hover state - [ ] Timing consistent (300ms recommended)