Expandable Card Grid
A free expandable card grid React component with native disclosures and Motion layout reflow.
Customise
Code
const items = [
{
id: "skyline",
title: "Skyline 50",
summary: "50 km, 2,150 m of climb, 12-hour cut-off.",
detail: <p>Saturday 6 June, 06:00 from the field barn at Wraycote.</p>,
},
// Add two to seven more stable-ID cards.
];
<CardExpandableGrid items={items} />Expandable Card Grid is a free expandable card grid React component for Next.js. Three to eight stable-ID cards use native details and summary elements, so every disclosure remains keyboard operable and its complete content stays in the document before JavaScript loads. The enhanced grid coordinates one open card in controlled or uncontrolled mode and lets that card span two or three desktop columns.
Motion projects each keyed card from its current position using transform-only layout animation. Detail copy reverses through opacity and a configurable vertical offset before the grid settles, rapid choices retarget the latest valid ID, mobile keeps a one-column reading order, and reduced motion makes every state change instant. Removing the active item resolves the grid closed, reordering preserves a surviving selection, and a controlled close returns focus to the summary before its detail becomes inert.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/card-expandable-gridUsage
import { CardExpandableGrid } from "@/components/card-expandable-grid";
const items = [
{
id: "research",
title: "Research",
summary: "The evidence behind the direction.",
detail: <p>Interview themes, constraints and opportunities.</p>,
},
{
id: "prototype",
title: "Prototype",
summary: "The interaction before production.",
detail: <p>A focused, testable model of the final experience.</p>,
},
{
id: "delivery",
title: "Delivery",
summary: "The system prepared for launch.",
detail: <p>Production code, documentation and rollout notes.</p>,
},
];
export function Example() {
return (
<CardExpandableGrid
items={items}
defaultActiveId="research"
columns={3}
expandedSpan={2}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | { id; title; summary; detail; media? }[] | required | Three to eight cards with unique stable IDs, visible title and summary copy, complete detail content and optional media. |
| activeId | string | null | undefined | Controlled open card ID. Invalid or removed IDs resolve to a closed grid. |
| defaultActiveId | string | null | null | Initially open stable ID in uncontrolled usage. |
| onActiveChange | (id: string | null) => void | undefined | Called after the visitor requests a native disclosure to open or close. |
| columns | 2 | 3 | 3 | Desktop column count. The grid remains one column on mobile. |
| expandedSpan | 2 | 3 | 2 | Desktop span of the open card, clamped to the available columns. |
| motionPreset | "snappy" | "soft" | "soft" | House spring preset for card reflow and detail movement. |
| contentOffset | number | 14 | Detail entrance distance in pixels, clamped from 0 to 28. |
| hoverLift | number | 4 | Closed-card hover and focus lift in pixels, clamped from 0 to 8 and disabled for touch or reduced motion. |
| radius | number | 20 | Card corner radius in pixels, clamped from 8 to 32. |
| className | string | undefined | Additional classes merged onto the semantic card list. |
Customisation
Use the six playground controls for grid geometry and effect behaviour. Five Tier 3 variables retheme the surfaces without editing the component: --card-expandable-grid-surface, --card-expandable-grid-border, --card-expandable-grid-accent, --card-expandable-grid-muted and --card-expandable-grid-media. Consumer media and detail nodes retain their own semantics and styling.
<CardExpandableGrid
items={items}
columns={2}
expandedSpan={2}
motionPreset="snappy"
contentOffset={20}
hoverLift={6}
radius={28}
/>
<style>{`
:root {
--card-expandable-grid-accent: var(--primary);
--card-expandable-grid-media: var(--surface);
}
`}</style>Frequently asked questions
- Is Expandable Card Grid free for commercial use?
- Yes. Expandable Card Grid is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Does the expandable card grid work without JavaScript?
- Yes. Every card contains a native details and summary disclosure, complete detail content is present in the server HTML, and the shared native name keeps one disclosure open at a time in supporting browsers. JavaScript only adds controlled state, focus restoration and Motion layout reflow.
- How does Expandable Card Grid handle accessibility and reduced motion?
- The native summary is the only disclosure control, visible title and summary copy never depend on position, and detail focus returns to that summary before a controlled close makes the content inert. Reduced motion disables layout, opacity, lift and transform animation synchronously, while mobile keeps a single-column source order.