ComponentsPanel
Page header
The top of a page: breadcrumb, title, description, meta and actions that fold into a menu when there is no room.
Import
import { PageHeader, PageHeaderBreadcrumb, PageHeaderHeading, PageHeaderTitle, PageHeaderMeta, PageHeaderDescription, PageHeaderActions, PageHeaderAction } from "@booleanpress/ui/page-header"Usage
Every admin page starts with one. The title is the page's h1; the actions sit at the end of its line.
import { PlusIcon } from "lucide-react"
import {
PageHeader,
PageHeaderAction,
PageHeaderActions,
PageHeaderDescription,
PageHeaderHeading,
PageHeaderTitle,
} from "@booleanpress/ui/page-header"
export function MailersHeader() {
return (
<PageHeader>
<PageHeaderHeading>
<PageHeaderTitle>Mailers</PageHeaderTitle>
</PageHeaderHeading>
<PageHeaderDescription>The connections your sites send email through.</PageHeaderDescription>
<PageHeaderActions>
<PageHeaderAction onSelect={() => {}}>Export</PageHeaderAction>
<PageHeaderAction pinned icon={<PlusIcon />} onSelect={() => {}}>Add mailer</PageHeaderAction>
</PageHeaderActions>
</PageHeader>
)
}PageHeaderBreadcrumb holds a Breadcrumb above the title. PageHeaderHeading is the title's line: PageHeaderTitle (an h1; as changes the level) and PageHeaderMeta for badges, avatars or a date beside it. PageHeaderDescription is the sentence under it.
PageHeaderActions takes PageHeaderActions, each a Button that runs onSelect. When the header is narrower than 36rem (its own width, not the window's), the actions that are not pinned fold into a "More actions" menu, and run the same onSelect from there; pinned keeps the page's main action a button; an icon-only action shows its aria-label as its text in the menu. collapse="always" or "never" decides once for all. The actions take at most 60% of the header's width and wrap past that, so a long title keeps its room. Put Tabs right after the header for the page's sections.
The examples on this page give the title as="h2", because the page already has its own h1; on a screen of your app, leave the default h1.
Examples
Basic
A title and a description.
import { PageHeader, PageHeaderDescription, PageHeaderHeading, PageHeaderTitle } from "@booleanpress/ui/page-header"
export default function PageHeaderBasic() {
return (
<PageHeader className="w-full">
<PageHeaderHeading>
<PageHeaderTitle as="h2">Email log</PageHeaderTitle>
</PageHeaderHeading>
<PageHeaderDescription>Every email your sites sent in the last 30 days.</PageHeaderDescription>
</PageHeader>
)
}With breadcrumb
A breadcrumb above the title.
With actions
Two actions and a pinned main action at the end of the title.
import { DownloadIcon, PlusIcon, SendIcon } from "lucide-react"
import {
PageHeader,
PageHeaderAction,
PageHeaderActions,
PageHeaderDescription,
PageHeaderHeading,
PageHeaderTitle,
} from "@booleanpress/ui/page-header"
export default function PageHeaderWithActions() {
return (
<PageHeader className="w-full">
<PageHeaderHeading>
<PageHeaderTitle as="h2">Mailers</PageHeaderTitle>
</PageHeaderHeading>
<PageHeaderDescription>The connections your sites send email through.</PageHeaderDescription>
<PageHeaderActions>
<PageHeaderAction icon={<DownloadIcon />}>Export</PageHeaderAction>
<PageHeaderAction icon={<SendIcon />}>Send test</PageHeaderAction>
<PageHeaderAction pinned icon={<PlusIcon />}>
Add mailer
</PageHeaderAction>
</PageHeaderActions>
</PageHeader>
)
}With meta
A status badge, the assignees and the last update beside the title.
import { Avatar, AvatarFallback, AvatarGroup } from "@booleanpress/ui/avatar"
import { Badge } from "@booleanpress/ui/badge"
import {
PageHeader,
PageHeaderAction,
PageHeaderActions,
PageHeaderDescription,
PageHeaderHeading,
PageHeaderMeta,
PageHeaderTitle,
} from "@booleanpress/ui/page-header"
export default function PageHeaderWithMeta() {
return (
<PageHeader className="w-full">
<PageHeaderHeading>
<PageHeaderTitle as="h2">Ticket #1041</PageHeaderTitle>
<PageHeaderMeta>
<Badge variant="warning">Waiting on customer</Badge>
<AvatarGroup>
<Avatar size="sm">
<AvatarFallback>AR</AvatarFallback>
</Avatar>
<Avatar size="sm">
<AvatarFallback>LW</AvatarFallback>
</Avatar>
</AvatarGroup>
<span>Updated 4 Oct 2026</span>
</PageHeaderMeta>
</PageHeaderHeading>
<PageHeaderDescription>Cannot connect to SES from the staging site.</PageHeaderDescription>
<PageHeaderActions>
<PageHeaderAction>Assign</PageHeaderAction>
<PageHeaderAction pinned>Reply</PageHeaderAction>
</PageHeaderActions>
</PageHeader>
)
}Narrow
Under 36rem the actions fold into a “More actions” menu; the pinned Edit stays a button.
import { CopyIcon, PauseIcon, PencilIcon, Trash2Icon } from "lucide-react"
import {
PageHeader,
PageHeaderAction,
PageHeaderActions,
PageHeaderDescription,
PageHeaderHeading,
PageHeaderTitle,
} from "@booleanpress/ui/page-header"
export default function PageHeaderNarrow() {
return (
<PageHeader className="w-full max-w-sm rounded-md border p-4">
<PageHeaderHeading>
<PageHeaderTitle as="h2">Transactional SES</PageHeaderTitle>
</PageHeaderHeading>
<PageHeaderDescription>Under 36rem the actions fold into “More actions”.</PageHeaderDescription>
<PageHeaderActions>
<PageHeaderAction icon={<CopyIcon />}>Duplicate</PageHeaderAction>
<PageHeaderAction icon={<PauseIcon />}>Pause</PageHeaderAction>
<PageHeaderAction icon={<Trash2Icon />} variant="destructive">
Delete
</PageHeaderAction>
<PageHeaderAction pinned icon={<PencilIcon />}>
Edit
</PageHeaderAction>
</PageHeaderActions>
</PageHeader>
)
}With tabs
Tabs right under the header for the page's sections.
import { PlusIcon } from "lucide-react"
import {
PageHeader,
PageHeaderAction,
PageHeaderActions,
PageHeaderHeading,
PageHeaderTitle,
} from "@booleanpress/ui/page-header"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@booleanpress/ui/tabs"
export default function PageHeaderWithTabs() {
return (
<div className="flex w-full flex-col gap-4">
<PageHeader>
<PageHeaderHeading>
<PageHeaderTitle as="h2">Customers</PageHeaderTitle>
</PageHeaderHeading>
<PageHeaderActions>
<PageHeaderAction pinned icon={<PlusIcon />}>
Add customer
</PageHeaderAction>
</PageHeaderActions>
</PageHeader>
<Tabs defaultValue="all">
<TabsList>
<TabsTrigger value="all">All</TabsTrigger>
<TabsTrigger value="active">Active</TabsTrigger>
<TabsTrigger value="archived">Archived</TabsTrigger>
</TabsList>
<TabsContent value="all" className="text-sm">2,418 customers.</TabsContent>
<TabsContent value="active" className="text-sm">2,106 active customers.</TabsContent>
<TabsContent value="archived" className="text-sm">312 archived customers.</TabsContent>
</Tabs>
</div>
)
}Accessibility
- Semantics
- A
divwith the title as a heading (h1by default). The actions are buttons; the folded ones are a dropdown menu (role="menu") behind a button witharia-haspopup="menu". - Labels
- The title is the page's main heading: one
h1per page, andasa lower level for a header inside a section. The menu button is named by the provider'smoreActionsstring. - Focus
- Nothing moves focus. The actions are in reading order, after the title; the menu returns focus to its button when it closes.
- Known limits
- Only
PageHeaderActions fold into the menu; other elements inPageHeaderActionsstay where they are. - The width where the actions fold is fixed at 36rem of the header's width.
- Only
Keyboard
| Key | Behaviour |
|---|---|
| EnterorSpace | Runs the focused action, or opens the “More actions” menu. |
| ↓or↑ | In the open menu, moves between the folded actions. |
| Escape | Closes the menu and returns focus to its button. |
API
PageHeader
Renders a div and passes it every other prop.
PageHeaderBreadcrumb
Renders a div and passes it every other prop.
PageHeaderHeading
Renders a div and passes it every other prop.
PageHeaderTitle
Renders a h1 and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
as | "h2" | "h3" | "h1" | "h4" | "h5" | "h6" | h1 | The heading level. h1 by default; a header inside a page section takes the level that fits the outline. |
PageHeaderMeta
Renders a div and passes it every other prop.
PageHeaderDescription
Renders a p and passes it every other prop.
PageHeaderActions
Renders a div and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
collapse | "auto" | "always" | "never" | auto | auto folds the actions into the menu when the header is narrow; always and never decide once for all. |
PageHeaderAction
| Prop | Type | Default | Description |
|---|---|---|---|
icon | ReactNode | An icon before the label, 14 px. | |
loading | boolean | Shows the spinner in place of the leading icon, sets aria-busy and aria-disabled and ignores presses (a click,
Enter, Space, a form's submission), while the button keeps its focus and its place in the tab order. With
asChild the child (a link) gets the same. | |
pinned | boolean | false | Keeps the action a button at every width, after the menu: the page's main action. |
raised | boolean | null | ||
rounded | boolean | null | ||
severity | "success" | "info" | "warning" | "help" | "danger" | "contrast" | null | ||
size | "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | Button's size. | |
variant | "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | Button's look: outline by default, default when pinned. destructive shows red in the menu too. |
Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.
Data attributes: data-slot="page-header" (PageHeader), data-slot="page-header-breadcrumb" (PageHeaderBreadcrumb), data-slot="page-header-heading" (PageHeaderHeading), data-slot="page-header-title" (PageHeaderTitle), data-slot="page-header-meta" (PageHeaderMeta), data-slot="page-header-description" (PageHeaderDescription), data-slot="page-header-actions" (PageHeaderActions), data-slot="page-header-action" (PageHeaderAction), and data-collapse.
Provider strings: moreActions (BooleanUIProvider's strings).
Theming
The title is --foreground, 20 px semibold; the description and meta --muted-foreground, 14 px. The actions are the library's Button and DropdownMenu.
The tokens its classes read. Change their values in your theme, and it follows.
| Token | Used for |
|---|---|
--foreground | text |
--muted-foreground | text |