GitHub

App Bar

The full-bleed chrome shell shared by top nav bars, sub-bars, and footers. It sets a color context (background + currentColor) from semantic tokens via tone, then exposes start / default / end slots. Children — Icon Link, Icon Button, a brand lockup — inherit the color, so a bar's brand comes entirely from tokens.

Stable .astro import EsaAppBar from '@esa/ecology/esa-app-bar.astro';

Tones

Each tone maps to ecology semantic tokens; a spoke re-themes by re-pointing those tokens (e.g. --color-background-brand, --color-background-default-knockout) — never by touching this component.

<EsaAppBar tone="surface">…</EsaAppBar>
<EsaAppBar tone="brand">…</EsaAppBar>
<EsaAppBar tone="brand-strong">…</EsaAppBar>

Slots: start · main · end

The end slot is pushed right with margin-left:auto. This is the whole anatomy of a top bar.

CB Fish
Dashboard
<EsaAppBar tone="brand" as="header">
  <span slot="start"><strong>CB Fish</strong></span>
  <EsaIconLink icon="trees" iconRight="chevron-down">Mitigation work</EsaIconLink>
  <EsaIconLink icon="trending-up" iconRight="chevron-down">Reporting</EsaIconLink>
  <EsaIconLink icon="credit-card" iconRight="chevron-down">Funding</EsaIconLink>
  <EsaIconButton slot="end" icon="search" label="Search" />
  <EsaIconLink slot="end" href="/dashboard" icon="layout-dashboard">Dashboard</EsaIconLink>
  <EsaIconLink slot="end" icon="circle-user" iconRight="chevron-down">Angela Zhao</EsaIconLink>
</EsaAppBar>

API

PropTypeDefaultDescription
tone 'surface' | 'brand' | 'brand-strong' 'surface' Color context. surface → --color-background-elevation-raised/text-primary; brand → --color-background-brand/text-inverse; brand-strong → --color-background-default-knockout/text-inverse. Children inherit the text color.
contained boolean false Constrain the inner row to maxWidth and center it.
maxWidth string '1556px' Inner row max-width when contained.
as 'header' | 'nav' | 'footer' | 'div' 'div' Semantic host element.
ariaLabel string — Accessible name for the host element. REQUIRED when as="nav" — an unnamed navigation landmark cannot be told apart from any other in a screen reader's landmark list, and this component spreads no rest props, so there was previously no way to name one. Omit the word "navigation": the role is announced already.
class string — Extra class on the root, for per-instance layout overrides.

Theming surface

Every public token this component reads, extracted from its source at build time, split by blast radius: the hooks that belong to this component, then the shared and system tokens it consumes alongside everything else. The Resolves to column walks each token's real lineage — component → semantic → primitive → raw value — so you can see exactly where re-pointing it lands. A spoke re-skins by overriding these in its theme-<slug>.css; component internals are never edited. No hook for what you need? File it with /request-lego.

Type roles it names

This component does not set a size, weight, face or tracking of its own — it names a composite, and the composite carries all five. A composite is a class rather than a token, so none of it appears in the tables below; re-theme text by re-pointing the token family, not by editing the component.

RoleRe-pointReach
.typography-label-md
  • --typography-label-md-font-family 'DM Sans', sans-serif via --typography-font-family-sans → --font-family-dm-sans
  • --typography-label-md-font-size clamp(0.75rem, 0.66rem + 0.44vw, 0.9375rem) via --font-size-200
  • --typography-label-md-font-weight 500 via --typography-font-weight-medium → --font-weight-500
  • --typography-label-md-letter-spacing 0.01em via --letter-spacing-default
  • --typography-label-md-line-height 1.6 via --line-height-normal
+33 more components esa-breadcrumbs, esa-button-group, esa-button-toggle, esa-card, esa-checkbox-group, esa-color-picker, esa-combobox, esa-command-palette, esa-confirm-dialog, esa-danger-zone, esa-date-picker, esa-dialog, esa-empty-state, esa-entity-search, esa-file-upload, esa-filter-container, esa-form-field, esa-header-nav, esa-input-tag, esa-link-column, esa-page-header, esa-pillbox, esa-popover, esa-progress-bar, esa-radio-group, esa-range-slider, esa-select, esa-side-dialog, esa-sidebar-nav, esa-stat, esa-text-field, esa-textarea, esa-tooltip

Wired to this component

None. This component has no hooks of its own — it themes entirely through the shared tokens below, so every override here also moves its siblings.

Shared tokens it reads

Owned by a family or by the semantic layer. Still overridable — but scope the override (esa-foo { --form-border-color: … }) unless you mean to move everything that reads it. Reach says what else that is.

Token Reach Resolves to
--color-background-brand semantic every component #46a758 via --color-grass-9
--color-background-default-knockout semantic every component #202020 via --color-gray-12
--color-background-elevation-raised semantic every component #fcfcfc via --color-gray-1
--color-content-default semantic every component #202020 via --color-gray-12
--color-content-default-knockout semantic every component #fcfcfc via --color-gray-1
--spacing-400 primitive every component 1rem
--spacing-600 primitive every component 2rem