Top Header Desktop
Desktop navigation bar with brand, nav, search, actions and subRow slots. Six variants, five sizes, radius cascade, true-centre nav, scroll elevation, floating inset mode, skip link, and full RTL support.
Playground
Installation
pnpm add @tessinaui/uiUsage
import {
TopHeaderDesktop,
TopHeaderDesktopBrand,
TopHeaderDesktopNavList,
TopHeaderDesktopNavItem,
TopHeaderDesktopActions,
} from "@tessinaui/ui";
import { Search } from "@tessinaui/ui"; // library Search in the search slot
import { IconButton } from "@tessinaui/ui"; // library IconButton in actions<TopHeaderDesktop
bordered
brand={
<TopHeaderDesktopBrand href="/" name="Tessina">
<img src="/logo.svg" alt="" className="size-7" />
</TopHeaderDesktopBrand>
}
nav={
<TopHeaderDesktopNavList>
<TopHeaderDesktopNavItem active href="/">Home</TopHeaderDesktopNavItem>
<TopHeaderDesktopNavItem href="/about">About</TopHeaderDesktopNavItem>
</TopHeaderDesktopNavList>
}
search={<Search variant="filled" rounded="full" placeholder="Search…" />}
actions={
<TopHeaderDesktopActions>
<IconButton variant="ghost" size="sm" aria-label="Notifications">
<Bell className="size-4.5" />
</IconButton>
</TopHeaderDesktopActions>
}
/>The bar publishes its tone through <Surface>, so library components dropped
into any slot — Button, IconButton, Avatar, Badge, Search — adapt to
primary / on-color / hero-overlay bars automatically.
Examples
Default
A basic desktop header with brand, nav, and trailing actions.
App shell
The product bar: workspace switcher in the brand slot, global search with a
⌘K hint, create action, notification badge, and an avatar account menu —
composed entirely from library components.
Commerce
Double-row store header: search-dominant main row, wishlist, cart count,
locale selector, and a category nav in the subRow slot with the underline
indicator.
Marketing
An announcement Banner stacked above the bar (a sibling — never a header
variant), a "New" badge on a nav item, a disabled item, and the quiet-login +
filled-signup pair.
Sub row
The subRow slot stacks any second row under the bar — here a Tabs strip.
It inherits the bar's horizontal padding and maxWidth containment.
Breadcrumb bar
The doc-tool pattern (Linear, Vercel, GitLab): a Breadcrumb trail as the
bar's leading content.
Transparent over a hero
variant="transparent" inside <Surface ink="light"> — the bar inherits the
plate's ink with no tone prop at all.
Blur + scroll elevation
variant="blur" + sticky + scrollBehavior="elevate": flat at rest, then a
hairline and shadow the moment content scrolls underneath.
Floating (inset)
inset detaches the bar from the screen edges; its shell corners join the
rounded cascade (full ⇒ rounded-3xl).
Active-item styles
indicator="pill" (default) vs indicator="underline", plus a disabled item
that drops its href and leaves the tab order.
Skip link
TopHeaderDesktopSkipLink — invisible until keyboard focus, the first Tab
stop, jumping straight to your content region (WCAG 2.4.1).
Dropdown menu
A nav item that opens a hover/focus dropdown — composed from NavigationMenu,
which owns the aria-expanded / keyboard contract.
Mega menu
Full-width mega menu with a two-column product grid and a promotional footer card.
Enterprise dashboard
Icon-labelled nav items, ghost icon actions, and a primary CTA.
Variants
The six visual styles.
Nav positions
start, center (truly centred — a 1fr auto 1fr grid, so the centre cell
holds position regardless of side widths), and end.
With search
The search slot fills the flex-1 middle zone, wrapped in a search
landmark.
Sizes
Five height and padding scales — the bar's controls and search step with them.
Loading
The built-in skeleton mirrors the header layout — including navPosition —
to avoid content shift.
API Reference
TopHeaderDesktop
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "filled" | "elevated" | "transparent" | "primary" | "on-color" | "blur" | "filled" | Visual style |
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Bar height scale — see the height table below |
rounded | "none" | "sm" | "md" | "lg" | "full" | "full" | Corner cascade for everything inside the bar (nav pills, search, icon buttons, skeleton bars) and, when inset, the shell itself. An attached bar's own corners stay square |
brand | ReactNode | — | Leading slot: logo, workspace switcher, breadcrumb |
nav | ReactNode | — | Navigation slot — position via navPosition |
navPosition | "start" | "center" | "end" | "start" | center is truly centred via a 1fr auto 1fr grid |
search | ReactNode | — | Search slot, rendered inside a search landmark |
actions | ReactNode | — | Trailing actions |
subRow | ReactNode | — | Second full-width row under the bar (tabs, category nav, breadcrumb strip) |
bordered | boolean | false | 1px bottom hairline |
sticky | boolean | false | sticky top-0 z-40 (top-3 when inset) |
inset | boolean | false | Floating bar: margins, hairline, shadow, shell corners from rounded |
scrollBehavior | "none" | "elevate" | "none" | elevate: data-scrolled + hairline + shadow once content scrolls under (IntersectionObserver sentinel; works in any scroll container) |
indicator | "pill" | "underline" | "pill" | Active nav-item treatment |
maxWidth | "sm" | "md" | "lg" | "xl" | "2xl" | "full" | "full" | Content-row containment — 48 / 64 / 72 / 80 / 96rem |
label | string | "Main" | Accessible name of the nav landmark — make it unique per page, never containing the word "navigation" |
skeleton | boolean | false | Loading placeholder |
dir | "ltr" | "rtl" | — | Direction |
tone | "default" | "on-color" | auto | Published via <Surface>; auto-on-color for primary/on-color variants, otherwise inherited from the surrounding Surface |
Bar heights: xs 48px · sm 56px · md 64px · lg 72px · xl 80px
(min-heights on the content row; xs/sm match Carbon's 48px shell and
Atlassian's 56px global nav).
TopHeaderDesktopSkipLink
First-Tab "Skip to content" link (WCAG 2.4.1). Render it first inside brand,
or GOV.UK-style immediately after <body>.
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | "#content" | Jump target — your main content region |
TopHeaderDesktopBrand
<a> (or anything via render) with focus ring and flex gap.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Brand name next to children |
href | string | — | Link destination |
render | ReactElement | fn | — | Replace the element — render={<Link href="/" />} |
TopHeaderDesktopNavList
<ul> container for nav items and dividers.
TopHeaderDesktopNavItem
<a> (or anything via render) styled as a nav link.
| Prop | Type | Default | Description |
|---|---|---|---|
active | boolean | false | Current page — aria-current="page" + the bar's indicator treatment |
disabled | boolean | false | aria-disabled, href dropped (leaves tab order), muted paint |
hasDropdown | boolean | false | Chevron only — compose NavigationMenu for a real menu |
render | ReactElement | fn | — | Replace the element — render={<Link href="/pricing" />} |
TopHeaderDesktopNavDivider
<li> vertical separator between nav items.
TopHeaderDesktopActions
Flex row wrapper for trailing action elements.
Deprecated sub-components
TopHeaderDesktopSearch, TopHeaderDesktopIconButton and
TopHeaderDesktopAvatar are deprecated (kept working for one minor).
Slot the library components instead — they carry the full contracts and adapt
to the header's Surface tone automatically:
| Deprecated | Use instead |
|---|---|
TopHeaderDesktopSearch | Search (variant="filled" rounded="full") |
TopHeaderDesktopIconButton | IconButton (variant="ghost") |
TopHeaderDesktopAvatar | Avatar inside a button / DropdownMenu trigger |
Variants
- Filled (default) — solid
bg-backgroundapp bar. - Elevated — filled +
shadow-sm, for bars floating over scrollable content. - Transparent — no fill; overlay a hero (
className="absolute inset-x-0 top-0") inside a<Surface ink>so the tone is inherited. - Primary — brand-coloured. Rare in the wild (3 of 206 surveyed headers) — prefer
filledoron-colorunless the brand calls for it. - On Color — dark plate with light ink; the common "dark bar on a light app" (24 of 206 surveyed).
- Blur — frosted glass; pair with
stickyandscrollBehavior="elevate".
Transparent and blur are marketing-page patterns — the survey found zero in product shells. Product bars are solid.
Boundaries
- Announcement strips stack a
Bannerabove the bar — never a header variant. - Real nav menus (
aria-expanded, hover intent, keyboard) come fromNavigationMenucomposed into thenavslot. - Collapsed/hamburger navigation belongs to
TopHeaderMobileandSidebar. - Auto-overflow "More" menu for crowded navs is tracked separately; until then keep ≤5 primary items (the Astryx doctrine).
- Keep one emphasized action in the bar (HIG) — everything else ghost/outline.
Keyboard Navigation
| Key | Action |
|---|---|
Tab / Shift+Tab | Move between the bar's interactive elements |
Enter / Space | Activate focused link or button |
Enter on skip link | Jump to the content region |
Menus composed via NavigationMenu add the full APG pattern: arrows rove
between triggers, ArrowDown enters an open panel, Home/End jump,
Esc closes and returns focus to the trigger.
Accessibility
- Renders
<header>without a hardcodedrole— it is abannerlandmark exactly when your page places it at body level (APG rule). <nav aria-label={label}>wraps the nav slot; setlabeluniquely per page and never include the word "navigation".- The search slot renders inside a
<search>landmark. - Active item:
aria-current="page". Disabled item:aria-disabled, nohref, out of the tab order. TopHeaderDesktopSkipLinkprovides the WCAG 2.4.1 bypass block.- Touch targets floor at 44px below
md; the deprecated search input floors at 16px text on phones (iOS zoom). - Focus rings visible on every interactive part, both themes.
dir="rtl"flips the layout via logical properties.- AT matrix: VoiceOver verified locally; NVDA and JAWS untested (no
Windows host) — status stays
betauntil a recorded NVDA pass.
Migration (from the pre-TES-35 API)
- Attached-bar corner rounding is gone:
roundedno longer curves the bar's own bottom edge (it drives the inner cascade, and the shell only wheninset). Want the old look? AddclassName="rounded-b-md"etc. maxWidthremap:lgis now 72rem (was 80),xlis 80rem (was a duplicate 1280px).2xl/sm/md/fullunchanged.rounded="xl"never existed — the old docs table was wrong; the scale isnone–full.TopHeaderDesktopToneis now an alias ofSurfaceTone.- The three deprecated sub-components keep rendering unchanged for one minor.