Navbar
The application header: brand, environment marker, and the actions that belong to the whole app rather than the current screen. This page's own header is the live demo. Not for the current page's own title or actions — the navbar is suite-level chrome, identical on every screen; the moment it carries "Purchase order PO-88213" or a Save button it stops being a fixed landmark and starts changing under the reader. Page identity belongs in the content area with the breadcrumb and heading, and a screen's actions in its own form actions bar. The boundary is drawn in full on the app frame pattern.
Brand, spacer, actions
One spacer element does the layout — everything before it sits at the start, everything after at the end. An environment badge (UAT, SANDBOX) next to the brand is the cheapest guard against someone approving a real invoice in a test system.
Markup
<header class="bo-navbar bo-app-shell__header">
<span class="bo-navbar__brand">busy-office ERP</span>
<span class="bo-badge bo-badge--accent">UAT</span>
<span class="bo-navbar__spacer"></span> <!-- pushes what follows to the end -->
<button class="bo-btn bo-btn--ghost bo-btn--icon" aria-label="Notifications">🔔</button>
</header> Quick reference generated
| Class | Role |
|---|---|
| .bo-navbar | block (root) |
| .bo-navbar__brand | part: brand |
| .bo-navbar__spacer | part: spacer |
API generated from CSS
| Blocks | bo-navbar |
|---|---|
| Parts | bo-navbar__brandbo-navbar__spacer |
| JS required | None — CSS-only. |
- Use a real
<header>; inside the app shell add.bo-app-shell__headerso it takes the shell grid slot. - The navbar is app-level. Screen-level actions belong in the page or the data-table toolbar, not up here.
- Icon-only buttons need an
aria-label— the icon is decoration.
Contrast — 15 AA pairs this component uses (generated, CI-gated)
| Text | on | Light | Dark |
|---|---|---|---|
| text-primary | bg-surface | 17.74 | 16.15 |
| text-primary | bg-canvas | 16.98 | 18.08 |
| text-secondary | bg-surface | 10.31 | 11.46 |
| text-muted | bg-surface | 7.56 | 6.65 |
| bg-surface | text-primary | 17.74 | 16.15 |
| danger-text | bg-surface | 6.47 | 8.89 |
| success-text | bg-surface | 5.02 | 12.02 |
| accent | bg-surface | 5.47 | 9.07 |
| text-primary | bg-hover | 16.12 | 13.75 |
| text-primary | bg-selected | 17.01 | 11.86 |
| text-primary | bg-surface-raised | 17.74 | 14.51 |
| border-control | bg-surface | 4.83 | 6.65 |
| --bo-state-error-color | bg-surface | 4.83 | 6.1 |
| warning-strong | bg-surface | 5.02 | 7.86 |
| text-primary | bg-muted | 16.12 | 13.75 |
Maturity generated
- Introduced
- v0.3.0
- CSS floor
- Chrome/Edge 99 · Firefox 97 · Safari 15.4
- Alignment scored
- 2026-08-23
- Assistive-tech evidence
- None recorded
Pin this component's first release with npm i @busy-office/ui@0.3.0.
The floor is derived from this component's stylesheet alone — set by
@layer — so it sits at or below the
whole framework's Chrome/Edge 119 · Firefox 129 · Safari 17.5.
No assistive-technology runtime result is recorded for any component: it needs a human listening to VoiceOver and NVDA on owner hardware; no gate in this repo can simulate announcement behaviour.
What automation covers instead is test:axe across every page at 1440 and 390, and check:forced-colors — see
accessibility.
Design-system alignment generated
100% (15/15) — how closely this component follows the design language. Each rule is scored 0-3 against a checkable citation; rules that don't apply leave the denominator. Scored 2026-08-23.
| Rule | Score | Evidence |
|---|---|---|
| Typography | 3 / 3 | no raw font-size; weight via --bo-font-weight-semibold |
| Colour | 3 / 3 | zero raw colour — surface/border/text all tokens |
| Spacing | 3 / 3 | the 3rem bar height states why it is a FLOOR and not a fixed height — a consistent landmark that must still grow for a taller control, which is also the WCAG 1.4.12 answer (94.6b) |
| Interaction | n/a | a container: it holds controls but introduces none of its own |
| Content | 3 / 3 | opener carries the wrong-choice clause: "Not for the current page's own title or actions" — suite-level chrome that starts carrying a record title or a Save button stops being a fixed landmark; points at breadcrumb + heading in the content area, a form-actions bar, and app-frame for the full boundary. Blind re-scored 2026-08-23 (Polish round 10), which independently confirmed the demo, the ApiTable note and the docs' own header all hold the same line. |
| Fit | 3 / 3 | the app top bar; po-app uses it at 3 sites (examples/po-app/server.mjs) |