Page Header React component for Tailwind CSS v4
v1.2.1Updated in 1.12.0
A React page header for admin screens: breadcrumb, title with avatar and badges, description, meta, actions that fold into a menu, and tabs.
Read where you are in the breadcrumb, then act: the primary action always stays in view at the end of the row, and the others fold one by one into a ⋯ menu as the window narrows (they come back when there is room). Actions that return a promise show a spinner until they finish. Tab walks the breadcrumb, the back button, every action and the ⋯ menu (arrow keys and Enter inside it, Escape closes it). With sticky set to condensed, scroll past the header and a glass bar with the title and the primary action slides down under the top bar. On a phone (or whenever the header itself is narrower than 512px, like in a side panel) the actions move under the title: the primary stays as a small button and the rest open from ⋯, as a bottom action sheet on phones (or stack full width with mobileActions set to stack); on phones the title shrinks and a ‹ back link replaces the breadcrumb.
Page Header is a Pro React component in the React layout components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add page-header, together with Avatar, Breadcrumb, Button, Dropdown Menu, Skeleton and 7 more and the npm packages motion and lucide-react.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add page-headerPage Header is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import PageHeader from @/components/ui/page-header.
import { Pencil, Plus, Trash2 } from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { NavTabs } from "@/components/ui/nav-tabs"
import { PageHeader } from "@/components/ui/page-header"
export function ClientHeader() {
return (
<PageHeader
breadcrumb={[
{ label: "Home", href: "/" },
{ label: "Clients", href: "/clients" },
{ label: "Tech Solutions LLC" },
]}
avatar={{ name: "Tech Solutions LLC" }}
title="Tech Solutions LLC"
badges={<Badge tone="success" dot>Active</Badge>}
description="IT equipment distributor in Austin · EIN 12-3456789"
meta={[{ label: "Client since Mar 12, 2024" }, { label: "Balance $12,480.00" }]}
actions={[
{ label: "Edit", icon: <Pencil /> },
{ label: "Delete", icon: <Trash2 />, tone: "danger" },
{ label: "New invoice", icon: <Plus />, primary: true, href: "/invoices/new" },
]}
tabs={
<NavTabs
items={[
{ label: "Overview", href: "/clients/tech-solutions" },
{ label: "Invoices", href: "/clients/tech-solutions/invoices", badge: 12 },
]}
/>
}
sticky="condensed"
/>
)
}Props
titledefault""ReactNodeThe page title, rendered as the page's one <h1> (headingAs changes the element).
headingAsdefault"h1""h1" | "h2" | "h3" | "div"The title's element. Keep h1 for the page's own header; use h2, h3 or div when the header sits inside a page that already has its h1 (a dialog, a card, a docs preview).
descriptiondefault""ReactNodeOne or two lines under the title, capped at a readable width.
breadcrumbBreadcrumbEntry[] | ReactNodeEntries render a Breadcrumb (it folds the middle when long and becomes a ‹ Parent link on phones). A node renders as is.
backHrefdefault""stringAdds a back button before the title (through NavLink). Below 640px it replaces the breadcrumb as a ‹ text link.
onBack() => voidRuns when the back button is pressed; without backHref the back button is a plain button.
backLabeldefault"Back"stringThe back button's accessible name, and its visible text on phones ("Invoices" reads ‹ Invoices).
iconReactNodeAn icon in a tinted tile before the title (40px, 48px at lg), colored by tone or color.
avatar{ src?: string; name: string; radius?: AvatarRadius }A photo or initials before the title, wins over icon. radius md (default) for companies, full for people.
badgesReactNodeStatus badges after the title; they wrap under it when space runs out.
metaPageHeaderMeta[] | ReactNodeSmall facts in a wrapping row under the description: { id?, icon?, label }[], with 14px icons. A node renders as is.
actionsPageHeaderAction[] | ReactNode{ id?, label, icon?, onSelect?, href?, variant?, tone?, primary?, disabled? }[]. The primary one (or the last solid) stays visible, last in the row; the others are outline buttons that fold into ⋯ from the end while they do not fit, and always in the compact layout (header narrower than 512px: phones, side panels). onSelect returning a promise shows the button loading. A node renders as is, without folding.
tabsReactNodeNavTabs (or a Tabs list) sitting on the header's bottom border.
childrenReactNodeExtra content between the title row and the tabs, such as filters or a progress bar.
sizedefault"md""sm" | "md" | "lg"Title 18 / 24 / 32px (18 / 22 / 26px on phones), with the icon tile and avatar scaled to match.
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"The media's color: the icon tile's soft tint, or the avatar's initials when there is no photo (neutral keeps the name-based color).
colordefault""stringAny CSS color for the icon tile or the avatar initials; replaces the tone. Leave empty to use the tone.
borderdefaulttruebooleanThe hairline under the header; tabs sit on it.
loadingdefaultfalsebooleanSkeletons in the shape of the title, description, meta and actions; the breadcrumb and tabs stay.
maxActionsdefault0numberThe most buttons in the wide row, the primary included (1: only the primary, everything else in ⋯). The rest always open from the ⋯ menu, whatever fits. 0: as many as fit.
mobileActionsdefault"menu""menu" | "stack"The compact layout (the header narrower than 512px, so every phone): the primary stays as a small button and the rest open from ⋯ (a bottom action sheet on phones), or every action stacks full width (48px, primary on top).
stickydefault"none""none" | "condensed"condensed: once the header scrolls under the top bar, a 48px glass bar with the title and the primary action slides down and pins at top: var(--topbar-offset, 0px).
moreLabeldefault"More actions"stringThe ⋯ button's accessible name and the phone action sheet's hidden title.
cancelLabeldefault"Cancel"stringThe cancel row at the bottom of the phone action sheet.
scrollTargetHTMLElement | Window | RefObject<HTMLElement | null> | nullWhat scrolls, for the condensed bar. Default: the nearest ScrollContainerProvider, else the window.
linkComponent(props: LinkComponentProps) => ReactNodeThe router link for link actions, the back link and the breadcrumb. Default: the LinkProvider's.
classNamesPartial<Record<PageHeaderSlot, string>>Classes for the parts: breadcrumb, row, back, media, heading, title, badges, description, meta, metaItem, actions, more, tabs, condensed, condensedTitle, condensedAction.
Examples
Minimal
A title, a description and one primary action.
Back button
backHref instead of a breadcrumb: an icon button on desktop, a ‹ Invoices link on phones. Actions that return a promise load.
Settings page
An icon tile in the brand tone and no actions.
Sizes
sm, md and lg: 18 / 24 / 32px titles with the tile scaled to match.
Loading
Skeletons in the exact shape of the title, description, meta and actions.
Compact actions
Under 512px of width (every phone): the primary stays and the rest open from ⋯ (a sheet on phones), or stack full width.
Dependencies
Files
- components/ui/page-header.tsx
FAQ
Is the React Page Header component free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Page Header?
Run npx wingo-ui@latest add page-header. It also adds the Wingo UI items it builds on (Avatar, Breadcrumb, Button, Dropdown Menu, Skeleton and 7 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/page-header.
How does Page Header behave on phones?
On a phone (or whenever the header itself is narrower than 512px, like in a side panel) the actions move under the title: the primary stays as a small button and the rest open from ⋯, as a bottom action sheet on phones (or stack full width with mobileActions set to stack); on phones the title shrinks and a ‹ back link replaces the breadcrumb.