ReferenceAppBar

The Reference shell's app bar, ready to go. The chrome that never changes ( LanguageSelector) is baked into the End slot, the brand variant is a simple prop, and the parts that depend on your app ( middle, account) come in as composition. One preset, one shell — and the same shape will repeat for <AppAppBar> and <PromotionAppBar> once their middles ship.

This pattern pairs with ReferenceMiddle: one wraps the Reference shell's middle, the other wraps its whole app bar. Want full control? Drop down to the <AppBar> primitive and put the canonical pieces together yourself.

Live demo

Running in bounded mode so the bar stays inside the demo box. Give the search trigger a try — the CommandPalette opens right over the page — and the language selector and sign-in button work too.

API shape — the three-category rule

Every slot in the Reference app bar falls into one of three buckets, and the preset's API follows straight from that.

Invariant content

Baked. Not a prop. LanguageSelector is invariant chrome on every shell — the preset just mounts it. The one per-deployment config it needs (cookieDomain) is forwarded. NavHistory (back / forward / recents) is baked into the Brand slot too, gated on onNavigate.

Enumerated content

Variant prop. Brand resolves between 'mark' and 'lockup'; mode resolves between 'edge' and 'bounded'. Finite, known sets — you just pick from the list.

Contextual content

Composition. Middle takes the search index and a navigate function; account takes the auth state and signInHref. Both vary by consumer and reactively respond to runtime state — they’re ReactNode props, not parametric options.

Props

brand
'mark' | 'lockup'

Default 'mark'. Mark for in-app surfaces; lockup for acquisition / marketing.

brandHref
string

Default '/'. Brand anchor target.

brandLabel
string

Default 'Halo — Home'. Accessible label on the brand anchor.

mode
'edge' | 'bounded'

Default 'edge'. Forwarded to <AppBar>.

onNavigate
(pathname: string) => void

Router navigate for the baked NavHistory (back / forward / recents in the Brand slot). Pass it to wire history; omit it for a Reference shell without. The app also records visits via recordNav.

navHistoryIcons
Record<string, ReactNode>

Optional icon-key → glyph map forwarded to NavHistory, for recents rows whose recorded visit carried an icon key.

middle
ReactNode

Required. Typically <ReferenceMiddle items={…} onNavigate={…} />.

account
ReactNode

Required. Typically <AccountSlot state={…} signInHref={…} />.

cookieDomain
string

Forwarded to the baked LanguageSelector. Pass '.halocompliance.com' in production for cross-subdomain.

onSlotError
(error: Error, info: ErrorInfo) => void

Fires when any of the AppBar’s per-slot boundaries catch (Brand / Middle / End). Same shape as the AppBar’s own prop.

onChromeError
(error: Error, info: ErrorInfo) => void

Fires when one of the baked chrome patterns (BrandSlot, LanguageSelector) catches inside its own ErrorBoundary. Chrome degrades silently to the user; this is the only developer signal.

Usage

The minimal Reference shelltsx
import {
  ReferenceAppBar,
  ReferenceMiddle,
  AccountSlot,
} from '@halo-compliance/ui'

<ReferenceAppBar
  onNavigate={navigate}
  middle={<ReferenceMiddle items={SEARCH_INDEX} onNavigate={navigate} />}
  account={<AccountSlot state="signed-out" signInHref={portalUrl} />}
/>
With every knobtsx
<ReferenceAppBar
  brand="lockup"
  brandHref="/"
  brandLabel="Halo Compliance Design System — Home"
  mode="edge"
  onNavigate={navigate}
  cookieDomain=".halocompliance.com"
  middle={
    <ReferenceMiddle
      items={SEARCH_INDEX}
      placeholder="Search docs"
      onNavigate={navigate}
      onError={reportChromeError}
    />
  }
  account={
    <AccountSlot
      state="signed-out"
      signInHref={portalUrl}
      onError={reportChromeError}
    />
  }
  onSlotError={reportChromeError}
  onChromeError={reportChromeError}
/>

When to reach for it

  • Use the preset when you're building a Reference shell — docs, knowledge base, design system. Match it and the bar stays consistent across every surface.
  • Drop down to <AppBar> when you need full control: a different middle (a Reference shell variant), a custom End-slot composition (a third invariant element), or a custom mode treatment.

Anti-patterns

  • Don’t expose what’s invariant. Language is on every shell on every surface — exposing it as a prop invites accidental removal. Bake it. Same rule applies if a future “audit log indicator” or similar becomes invariant.
  • Don’t turn composition slots into prop bags. The temptation is to flatten middle=<ReferenceMiddle items={…} /> into middleItems={…}. Don’t — middle has half a dozen optional knobs (onError, shortcutMatcher, shortcutHint, placeholder, …) that would all have to flatten too. Composition keeps the API stable as the inner pattern grows.
  • Don’t reach for the preset when you need a different shell. An App-shell AppBar (⌘K + tenant + alerts) is a different preset, not a customized Reference one. <AppAppBar> ships when <AppMiddle> lands.
  • /app-bar — the AppBar Component this preset composes. Drop down to it for hand-composed shells.
  • /app-bar#middle — the middle slot and its shell-conditional content. ReferenceMiddle is the canonical Reference fill.
  • /app-bar#language — LanguageSelector, baked into this preset’s End slot.
  • /shell — how the bar mounts inside SiteLayout.