Layout Atoms
Available via @stackmates/ui-interactive/atoms
Card
Compound card container with header, title, description, content, and footer slots.
Full card with all slots
Project Overview
A summary of your current project status and milestones.
3 tasks completed, 2 in progress, 1 pending review.
Card without footer
Notification
You have 3 unread messages.
- New comment on Deal #42
- RFP proposal submitted
- Contact updated
Stats widget cards
Total Revenue
$45,231
+20.1% from last month
Active Deals
12
+3 new this week
CardProps
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | Additional CSS classes on the card container |
| children* | ReactNode | — | Card content — compose with CardHeader, CardContent, CardFooter |
CardHeaderProps
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | Header content — typically CardTitle and CardDescription |
| className | string | — | Additional CSS classes |
CardTitleProps
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | Title text content |
| className | string | — | Additional CSS classes |
Installation
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from '@stackmates/ui-interactive/atoms';Usage
Basic card
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Description</CardDescription>
</CardHeader>
<CardContent>Content here</CardContent>
<CardFooter>Footer actions</CardFooter>
</Card>Stats widget
<Card>
<CardHeader className="pb-2">
<CardDescription>Revenue</CardDescription>
<CardTitle className="text-3xl">$45,231</CardTitle>
</CardHeader>
<CardContent>
<p className="text-xs text-muted-foreground">+20% from last month</p>
</CardContent>
</Card>Accessibility
- CardTitle renders as <h3> for proper heading hierarchy within the card
- CardDescription renders as <p> for semantic paragraph content
- All sub-components support data-slot attributes for test selectors
AspectRatio
Radix-based container that maintains a specified width-to-height ratio for its content.
16:9
4:3
AspectRatioProps
| Prop | Type | Default | Description |
|---|---|---|---|
| ratio | number | 1 | Aspect ratio as width / height (e.g. 16/9) |
| children* | ReactNode | — | Content to render inside the aspect ratio container |
| className | string | — | Additional CSS classes |
Installation
import { AspectRatio } from '@stackmates/ui-interactive/atoms';Usage
16:9 video container
<AspectRatio ratio={16 / 9}>
<img src="/thumbnail.jpg" alt="Video" className="h-full w-full object-cover rounded-md" />
</AspectRatio>Square (1:1)
<AspectRatio ratio={1}>
<div className="flex items-center justify-center h-full bg-muted rounded-md">
Square content
</div>
</AspectRatio>Accessibility
- Built on Radix AspectRatio primitive with proper overflow handling
- Content inside receives full width and height of the ratio container
- Does not interfere with child element focus or keyboard navigation
Collapsible
Radix-based expand/collapse primitive with trigger and content slots.
CollapsibleProps
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | — | Controlled open state |
| onOpenChange | (open: boolean) => void | — | Callback when open state changes |
| defaultOpen | boolean | false | Initial open state (uncontrolled) |
| disabled | boolean | false | Prevent opening/closing |
Installation
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
} from '@stackmates/ui-interactive/atoms';Usage
Controlled
const [open, setOpen] = useState(false);
<Collapsible open={open} onOpenChange={setOpen}>
<CollapsibleTrigger>Toggle</CollapsibleTrigger>
<CollapsibleContent>Hidden content</CollapsibleContent>
</Collapsible>Default open
<Collapsible defaultOpen>
<CollapsibleTrigger>FAQ Item</CollapsibleTrigger>
<CollapsibleContent>Answer text</CollapsibleContent>
</Collapsible>Accessibility
- Built on Radix Collapsible with aria-expanded on trigger and aria-controls linking
- CollapsibleTrigger supports asChild for custom trigger elements
- Keyboard accessible via Enter/Space to toggle open state