Patterns
Application recipes built from existing components — filter bars, inline calls to action, and an index of every recipe on the component pages.
Last updated
Patterns are compositions, not components: copy the markup and change it. Each one uses only components you already have.
Recipe index
| Recipe | Where |
|---|---|
| Page header (breadcrumbs, back link, actions, search) | SectionHeader |
| Card header with actions and a menu | Card |
| Table card (title, table, pagination footer) | Table |
| Metric card | Stat |
| Dialog bodies (confirm, form, media, drawer) | Dialog |
| Activity feed | Timeline |
| Conversation and composers | Message |
| Sidebar groups, headings, featured card | Sidebar |
| Table footer with page size | Pagination |
| Date inputs | Input |
| Upload list | FileUpload |
| Tabbed install commands | Code |
| Notification count on an icon button | Button |
| Account switcher crumb | Breadcrumbs |
Filter bar
Search, a period switch and a Filters popover holding a GET form: the filters submit with zero JS and the server renders the filtered page. Clear is a link to the unfiltered URL, not a reset button: a reset would restore the values the server just rendered. The badge on the trigger counts the applied filters.
Show codeHide code
<div class="flex flex-wrap items-end gap-3">
<div class="min-w-48 flex-1"><Input aria-label="Search projects" placeholder="Search"><Search slot="start" /></Input></div>
<SegmentedControl aria-label="Period" options={['7d', '30d', '12m']} value="30d" />
<Popover id="filters" width="20rem" placement="bottom-end">
<Button slot="anchor" popovertarget="filters" variant="outline" color="neutral">
<Filter slot="start" />Filters<Badge slot="end" size="small" rounded>2</Badge>
</Button>
<form method="get" class="flex flex-col gap-3">
<Select label="Status" name="status">…</Select>
<Select label="Owner" name="owner">…</Select>
<div class="flex justify-end gap-2">
<Button href="?" variant="ghost" color="neutral" size="small">Clear</Button>
<Button type="submit" size="small">Apply</Button>
</div>
</form>
</Popover>
</div>Inline calls to action
Primary action on top on phones (flex-col-reverse), side by side from sm;
a media card; an email capture whose button lines up with the field; a
checklist.
Upgrade to Pro
Unlimited projects and priority support.
Invite your team
Projects move faster with more hands.
- Shared boards
- Comments and mentions
- Role-based access
Get the changelog
Show codeHide code
<Card>
<Heading as="h3" size="h4">Upgrade to Pro</Heading>
<Text size="small" color="neutral-faded">Unlimited projects and priority support.</Text>
<div class="mt-4 flex flex-col-reverse gap-3 sm:flex-row sm:justify-end">
<Button variant="outline" color="neutral">Compare plans</Button>
<Button>Upgrade</Button>
</div>
</Card>
<Card mediaPosition="start">
<img slot="media" src="…" alt="" />
<Heading as="h3" size="h4">Invite your team</Heading>
<Text size="small" color="neutral-faded">Projects move faster with more hands.</Text>
<ul class="mt-3 flex flex-col gap-1.5 text-sm">
<li class="flex items-center gap-2"><CircleCheck class="size-4 text-positive" aria-hidden="true" />Shared boards</li>
…
</ul>
<Button class="mt-4" size="small">Send invites</Button>
</Card>
<Card>
<Heading as="h3" size="h4">Get the changelog</Heading>
<form class="mt-3 flex flex-col gap-3 sm:flex-row sm:items-end">
<div class="flex-1"><Input label="Email" type="email" placeholder="you@example.com" /></div>
<Button type="submit">Subscribe</Button>
</form>
</Card>