Organism · stable · v1.0.0 · owner: Site system lead · contract 19 of 20 points (open: figma)
Do and don't
Do: English header
Rendered by header.tsShown live at the top and the foot of this page.
Do: Japanese header with current English destination
Rendered by header.tsShown live at the top and the foot of this page.
Don't: Two calls to action
Rendered by header.tsShown live at the top and the foot of this page.
Don't: A header that hides the language switch on some pages
Rendered by header.tsShown live at the top and the foot of this page.
Rules
| Rule | Why | Check |
|---|---|---|
| Every built page uses this header. | One navigation everywhere. | Automated: scripts/site/system/check-pages.ts (header on every page) |
| The language switch is on every page; a page without Japanese links to the Japanese home and says so. | The header never shifts, and readers are told where the link goes. | Automated: tests/site (language switch spec) |
API
| Prop | Type | Required | Default | What it does |
|---|---|---|---|---|
lang | en | ja | Yes | Page language. | |
path | string | Yes | The current path (marks the current section and page). | |
nav | list | Yes | The navigation groups (content/nav). | |
navSimple | list | No | The simple navigation variant. | |
alternates | object | No | The page's English and Japanese paths. | |
banner | string | No | The Japanese review banner. |
Contract details
The full contract: identity, anatomy, variants, states, tokens, layout, motion, accessibility, content, tests
Identity
| Aspect | Value |
|---|---|
| Id | header |
| Layer | Organisms |
| Category | navigation |
| Owner | Site system lead |
| Status | stable |
| Version | 1.0.0 |
| Source | apps/showcase/site/system/organisms/header.ts (private repository; the contract and the render function are this one module) |
| Version | Date | Change |
|---|---|---|
| 1.0.0 | 2026-10-26 | Site header as one module: its markup moved out of the page builder (scripts/site) into the system. |
Use when
- Every page built by the site builder. Why: One header everywhere means readers never relearn the navigation.
Do not use when
- Inside the product tour. Why: The tour has the product's own header.
Anatomy
| Part | What it is |
|---|---|
| skip | a.skip-link (rendered by the page shell, before the header) |
| root | header.site-header |
| logo | a.wordmark with the Logo |
| nav | nav.mega: details.mega-item per section (summary, div.mega-panel with mega-intro and mega-links); plain sections are a.mega-link |
| simple | nav.simple-nav when the navigation variant is simple |
| actions | div.header-actions: LanguageSwitch, Button (small), details.drawer |
| drawer | nav.drawer-panel: the same sections, then drawer-foot with two buttons |
| banner | p.review-banner on Japanese pages |
Made of: logo, language-switch, button, arrow-link, icon.
Used in: atomic-guide, page-apps, page-article, page-articles, page-deep, page-demo, page-hub, page-landing, page-404, page-status, page-runs-on-loom.
Variants
| Variant | When | Why |
|---|---|---|
| mega | The default. | Each section shows its pages with one line each. |
| simple | nav.variant: simple. | A flat list for a smaller site. |
States
| State | Rendered or not applicable |
|---|---|
| default | Closed menus. |
| hover | Section labels underline in the section's thread colour. |
| focus-visible | The --focus ring on every summary and link. |
| active | Not applicable: Links and summaries have no pressed style of their own. |
| disabled | Not applicable: Nothing in the header is disabled. |
| loading | Not applicable: Build time; the menus work without JavaScript (details). |
| empty | Not applicable: The navigation is required; the build fails without it. |
| error | Not applicable: No data that can fail. |
| current | The current section's summary is underlined with aria-current=true; the current page link has aria-current=page. |
| visited | Not applicable: Navigation links do not change colour when visited. |
| expanded | An open mega-menu or drawer (details[open]); one at a time (site.js closes the others). |
Tokens
| Part | Token |
|---|---|
| root.background | --cotton |
| root.border | --rule-hair --line |
| thread.underline | --thread (the section's dye) |
| panel.background | --surface |
| panel.shadow | --elevation-2 |
| --header-left-space-5 | var(--space-5) |
| --header-top-space-13 | var(--space-13) |
| --header-padding-space-5 | var(--space-5) |
| --header-padding-space-6 | var(--space-6) |
| --header-background-ink | var(--ink) |
| --header-color-cotton | var(--cotton) |
| --header-font-type-strong | var(--type-strong) |
| --header-top-space-5 | var(--space-5) |
| --header-background-cotton | var(--cotton) |
| --header-border-bottom-rule | var(--rule) |
| --header-border-bottom-ink | var(--ink) |
| --header-gap-space-5 | var(--space-5) |
| --header-min-height-header-h | var(--header-h) |
| --header-font-type-small-strong | var(--type-small-strong) |
| --header-padding-space-4 | var(--space-4) |
| --header-padding-space-2 | var(--space-2) |
| --header-gap-space-4 | var(--space-4) |
| --header-gap-space-1 | var(--space-1) |
| --header-margin-right-space-4 | var(--space-4) |
| --header-font-family-font-display | var(--font-display) |
| --header-border-right-rule-hair | var(--rule-hair) |
| --header-border-bottom-rule-hair | var(--rule-hair) |
| --header-transition-dur-moderate | var(--dur-moderate) |
| --header-transition-ease-standard | var(--ease-standard) |
| --header-right-space-5 | var(--space-5) |
| --header-bottom-rule | var(--rule) |
| --header-height-rule | var(--rule) |
| --header-background-saffron | var(--saffron) |
| --header-transition-dur-slow | var(--dur-slow) |
| --header-margin-top-rule | var(--rule) |
| --header-background-surface | var(--surface) |
| --header-box-shadow-shadow-float | var(--shadow-float) |
| --header-border-top-rule-frame | var(--rule-frame) |
| --header-border-top-ink | var(--ink) |
| --header-gap-space-10 | var(--space-10) |
| --header-padding-top-space-9 | var(--space-9) |
| --header-padding-bottom-space-9 | var(--space-9) |
| --header-color-ink | var(--ink) |
| --header-font-type-h3 | var(--type-h3) |
| --header-letter-spacing-ls-h3 | var(--ls-h3) |
| --header-margin-top-space-4 | var(--space-4) |
| --header-color-ink-2 | var(--ink-2) |
| --header-margin-top-space-6 | var(--space-6) |
| --header-font-weight-weight-strong | var(--weight-strong) |
| --header-gap-space-2 | var(--space-2) |
| --header-gap-space-8 | var(--space-8) |
| --header-border-top-rule-hair | var(--rule-hair) |
| --header-border-top-line | var(--line) |
| --header-border-top-color-ink | var(--ink) |
| --header-font-type-small | var(--type-small) |
| --header-text-decoration-thickness-rule-hair | var(--rule-hair) |
| --header-text-underline-offset-space-2 | var(--space-2) |
| --header-animation-dur-slow | var(--dur-slow) |
| --header-animation-ease-enter | var(--ease-enter) |
| --header-padding-gutter | var(--gutter) |
| --header-background-surface-2 | var(--surface-2) |
| --header-border-rule-hair | var(--rule-hair) |
| --header-border-ink | var(--ink) |
| --header-border-radius-radius | var(--radius) |
| --header-top-header-h | var(--header-h) |
| --header-top-rule | var(--rule) |
| --header-padding-space-10 | var(--space-10) |
| --header-border-bottom-line | var(--line) |
| --header-padding-space-8 | var(--space-8) |
| --header-gap-space-3 | var(--space-3) |
| --header-t-thread | var(--thread) |
Layout
| Aspect | Value |
|---|---|
| breakpoints | Checked at 390, 768, 1024 and 1440 px; the mega navigation from 1024 px, the drawer below it. |
| wrapping | Section labels never wrap; the drawer lists wrap. |
| textExpansion | Japanese labels are shorter in characters but wider in glyphs; checked at 1024 px with all five sections. |
Spacing and rhythm
| Aspect | Value |
|---|---|
| internal | 64 px tall; --space-5 between sections. |
| external | Sticky at the top. |
| rhythm | Always first. |
Motion
| Aspect | Value |
|---|---|
| moves | The mega panel and the drawer open. |
| trigger | Click, Enter or Space on a summary. |
| duration | --dur-quick |
| easing | --ease-standard |
| interruptible | Yes: Escape closes, and opening another section closes the first. |
| reduced | Panels appear without movement. |
| why | A short reveal shows where the panel came from. |
Runtime and reuse
Render-only element; mount any registered child enhancements separately. Preserve required Site CSS, fonts, responsive and locale rules from nativeElement.
Accessibility passport
| Aspect | Value |
|---|---|
| role | banner landmark; navigation landmarks named Main |
| name | Main |
| keyboard | Tab through sections; Enter or Space opens; Escape closes and returns focus to the summary. |
| focus | The --focus ring; focus is never trapped. |
| screenReader | details/summary announce expanded and collapsed; current page and section are announced. |
| contrast | Ink on cotton 14:1. |
| target | Section labels and buttons are 44 px tall. |
Content
| Slot | Length | Voice |
|---|---|---|
| section | 1 word | Section name |
| item description | 8 words | What the page gives |
Good: “Product · See · Know what you really have.”
Bad: “Platform” · “Solutions for enterprises”
Japanese: Labels from nav-ja; English-only pages are marked (英語).
Icons and illustrations
None: this element uses no icon or illustration of its own.
Decisions and exceptions
- None.
Usage
2109 uses across the built pages (measured by npm run site:system).
Tests
| Aspect | Value |
|---|---|
| unit | tests/unit/site-system.test.ts: renders every do and don't example through the registry and checks the classes it owns |
| visual | Not yet: there are no screenshot baselines; the Library page is checked for sideways scroll at 1440 px by tests/site/system.spec.ts |
| a11y | tests/site/system.spec.ts: axe (0 serious or critical) on the element's Library page in light and dark |
| parity | scripts/site/system/check.ts: Library examples are rendered by the same render function the site imports |
Figma
not-yet: The Loom Site Figma library is the last stage of the plan; this element is not mapped yet.