App Header
The top bar of an application: a slot for a sidebar toggle, the breadcrumbs, a search button that opens your command palette, your own actions, a notifications bell with an unread count and the account menu. In a narrow space the search folds to an icon.
A ready-made piece, built from the library's own parts.
A block puts several components together into something you would otherwise assemble by hand. It never fetches data: you give it the data, or answer its callbacks. It is copied into your project like any component, with the parts it uses, so you can change anything.
Basic
With breadcrumbs
With notifications
3 unread notifications
Compact
Permissions
ClassNames
Installation
npx rdloom add app-headerCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/app-header.jsonWorks, but without upgrade tracking.
Usage
import { AppHeader, CommandItem, CommandPalette, UserMenu } from "@rdloom/react";
<div className="mx-auto w-full max-w-4xl overflow-hidden rounded-xl border border-[var(--rd-color-border-default)]">
<AppHeader
onSearch={() => setOpen(true)}
userMenu={<UserMenu user={{ name: "Ada Lovelace", email: "ada@example.com" }} onSignOut={async () => {}} />}
/>
<CommandPalette label="Command palette" isOpen={open} onOpenChange={setOpen}>
<CommandItem id="new-invoice">New invoice</CommandItem>
<CommandItem id="open-settings">Open settings</CommandItem>
</CommandPalette>
<div className="h-24" />
</div>API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
leadingContent at the very start, such as the button that opens or folds the sidebar. Give it an accessible name. | node | none |
breadcrumbsWhere the person is, usually Breadcrumbs. It takes the free space and shortens before anything else. | node | none |
onSearchShows the search button and calls this when it is pressed, e.g. to open a CommandPalette. The shortcut shown on it is a hint only: wire the key yourself. | () => void | none |
searchLabelText and accessible name of the search button. | string | "Search" |
searchShortcutThe shortcut hint on the search button, keys separated by a space. Shown only where there is room. Pass an empty string to hide it. | string | "Ctrl K" |
onNotificationsShows the notifications bell and calls this when it is pressed, e.g. to open a panel. | () => void | none |
notificationCountHow many notifications are unread. Drawn as a badge (99+ above 99) and read with the button's name. Zero or none draws no badge. | number | 0 |
notificationsLabelAccessible name of the bell. The count is added: "Notifications, 3 unread". | string | "Notifications" |
actionsYour own buttons, before the bell and the account menu. | node | none |
userMenuThe account menu at the end, normally a UserMenu. | node | none |
permissionsWhat the person may do: { search, notifications } as "allow" (default), "disabled" or "hidden", or { state, reason }. A disabled button stays focusable (aria-disabled) and says why. The server must check again. | Permissions<"search" | "notifications"> | none |
labelAccessible name of the header landmark. | string | "Application header" |
sizedefault is 56 px high; compact is 44 px with smaller controls. | "default" | "compact" | "default" |
borderDraw a line under the header. | boolean | true |
stickyKeep the header at the top while the page scrolls. | boolean | false |
classNamesClass names for the parts, by slot name, added after the built-in ones. Slots: root, leading, breadcrumbs, search, shortcut, actions, notifications, badge, user-menu. | Partial<Record<"root" | "leading" | "breadcrumbs" | "search" | "shortcut" | "actions" | "notifications" | "badge" | "user-menu", string>> | none |
Accessibility
Role banner, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
- Tab: moves through the leading control, the breadcrumbs, search, your actions, the bell and the account menu, in that order
- Enter or Space: presses a button
Screen readers announce
- "Application header, banner"
- "Search, button"
- "Notifications, 3 unread, button"
- "Account menu, Ada Lovelace, menu button"
What your code must do
- The bar is a header landmark with its own name; use one per page and keep the page's main landmark outside it
- The search button has a visible name, or an accessible name when it folds to an icon; the shortcut hint is for sighted keyboard users and is hidden from screen readers so the name is not read twice
- The bell is named with the unread count ("Notifications, 3 unread"); the badge is drawn as a number, not as color alone
- A disabled button stays focusable (aria-disabled) and its reason is read with it
- The breadcrumbs keep their own navigation landmark
Block contract
- Data
- A notification count and the slots you fill: breadcrumbs, actions and the account menu.
- Data states
- None: it shows what it is given
- Permissions
- search, notifications
- Events
- onSearch, onNotifications
- You can replace
- leading, breadcrumbs, actions and userMenu slots; size, border and sticky; classNames for each part
Guidelines
Use it when
- The bar across the top of an application page, inside or beside a sidebar
- You want search, notifications and the account menu in one consistent place on every page
Avoid it when
- You need the whole frame with the sidebar and the phone menu: use DashboardShell
- Navigation across the top of a marketing site: use TopNav
- A title and the actions for one page: use PageHeader below the bar
Don't
- A second search field in the page next to the search button: one search entry point
- A count badge with no number for screen readers: set notificationCount instead of drawing your own dot
- More than two or three buttons in the actions slot: move the rest into a menu
- UI permission is not security: hiding or disabling a button only changes what people see, so the server must check again for every request
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-surface-default--rd-color-surface-subtle--rd-color-border-default--rd-color-border-strong--rd-color-text-default--rd-color-text-muted--rd-color-action-primary--rd-color-action-on-primary--rd-color-focus-ring--rd-radius-control--rd-size-control-sm