Section Header
betaA plain section title on the page, with an optional count and actions at the end of the row, that sits above a card.
Preview
section
Needs you
lg
Schedule
md
Members
sm
Coming up
narrow
Results from the quarterly customer survey
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the component.
npx shadcn@latest add @txbrendan/section-header
Use it for
- Title every card from outside it, on the page: the header, then the card 8px under it.
- Put the header and its card in one grid with gap-2. Start the next header 16px under the card.
- Pass count as a number for a quiet total, like Needs you 5.
- Pass your own Badge as count when the number needs a tone, like a warning.
- Put the section's actions in children, as ghost Buttons, like See all.
- Use size="lg" for the page title, the default md for sections, and sm for sections in a side rail.
Avoid it for
- A title row inside the card. Title it from outside with this.
- Long sentences as a title. Keep it to a few words.
- Solid buttons in the actions. They pull the eye from the content. Use ghost Buttons.
- Skipping heading levels. Pass as="h3" when the header sits inside an h2 section.
Props
- title
The section's name, like "Needs you". Required.
ReactNode
- count
A number or string shows in a soft neutral Badge after the title. Pass your own element for a tone.
number | string | ReactElement
- size
lg is a 20px page title, md a 16px section title, and sm a 13px title for a side rail.
"sm" | "md" | "lg" · default "md"
- as
The heading level. Default h1 for lg, and h2 for md and sm.
"h1" | "h2" | "h3" | "h4" | "h5" | "h6"
- children
Actions at the end of the row, like ghost Buttons.
ReactNode
- className
Extra classes on the row. Later classes win, so className='min-h-0' drops the held height.
string
| Prop | Type | Default | What it does |
|---|---|---|---|
| title | ReactNode | - | The section's name, like "Needs you". Required. |
| count | number | string | ReactElement | - | A number or string shows in a soft neutral Badge after the title. Pass your own element for a tone. |
| size | "sm" | "md" | "lg" | "md" | lg is a 20px page title, md a 16px section title, and sm a 13px title for a side rail. |
| as | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | - | The heading level. Default h1 for lg, and h2 for md and sm. |
| children | ReactNode | - | Actions at the end of the row, like ghost Buttons. |
| className | string | - | Extra classes on the row. Later classes win, so className='min-h-0' drops the held height. |
Accessibility
- The title is a real heading, h2 by default, so screen readers list the section in the page outline.
- The count sits inside the heading, so the heading reads as "Needs you 5".
- The actions sit outside the heading, so the heading's name stays short.
- Give each action a name that makes sense alone, like "See all members", or put the section name in its aria-label.
- Title text is the page's foreground color, which the theme tests hold to 4.5:1 in light and dark.
Examples
A section over a card (needs @txbrendan/button and card)
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
<div className="grid gap-2">
<SectionHeader title="Needs you" count={5}>
<Button emphasis="ghost" size="sm">
See all
</Button>
</SectionHeader>
<Card>…</Card>
</div>A toned count (needs @txbrendan/badge)
import { Badge } from "@/components/ui/badge";
<SectionHeader
title="Needs you"
count={
<Badge tone="warning" emphasis="soft" size="sm">
3
</Badge>
}
/>The page title
<SectionHeader size="lg" title="Schedule" />A side rail section
<SectionHeader size="sm" title="Coming up" count={2} />