Component catalog
Every esa-* lego the package ships, in one scannable index — the fastest way to answer "does a component for this already exist?" before you build one. Each row links to its full doc page; the Layout & Sections group is where the section-level legos (esa-app-shell, esa-page-header, esa-stat) live.
Core
| Component | Kind | What it is | Props |
|---|---|---|---|
Button esa-button | .astro | Variant model aligned to Beacon's UiButton (two independent axes + toggle): - variant: primary | secondary | danger | success | warning | info | ai | ghost - appearance: fill | outline | dashed | sof… | variant? appearance? active? size? disabled? loading? icon? iconRight? iconOnly? label? current? type? tag? href? target? rel? class? color? |
Button Group esa-button-group | web component | groups slotted <esa-button> elements with connected borders. Faithful port of the Angular esa-button-group: selectionMode 'none' (visual grouping) or 'single' (radio-like segmented control). | interactive (Lit) |
Button Toggle esa-button-toggle | web component | Group label and segment text are both UI text (medium). The SELECTED segment steps up to semibold, which is what the -strong weight axis is for — it is not a size change, so the rung stays the same. | interactive (Lit) |
Icon esa-icon | .astro | hub-edit-approved: Andy approved (2026-06-15) — the Lucide glyph lookup moved to the shared ./icon-registry module so the SAME map feeds both this server component and the client-side esa-sidebar-nav… | name size? label? paths? |
Layout & Sections
| Component | Kind | What it is | Props |
|---|---|---|---|
App Shell esa-app-shell | .astro | CANONICAL application shell . The house chrome: NEUTRAL off-white surfaces layered by value (canvas < bar < rail), a sidebar toggle in the TOP-LEFT corner, the logo at the TOP OF THE SIDENAV, a compa… | title? active? items? userMenu? userName? searchIndex? searchPlaceholder? mark? brandHref? accent? collapsed? id? |
Page Header esa-page-header | .astro | The standard prototype page header: optional breadcrumbs OR an eyebrow (with an optional leading icon), a title (heading-lg by default, or the oversized display via prominence="display"), and a right… | title meta? eyebrow? icon? prominence? as? |
Stat esa-stat | .astro | A big display value, a readable label, and an optional supporting datum. Replaces the bespoke .stat / .stat__value / .stat__label / .stat__sub cluster every prototype re-implements. | value label sub? accent? |
Container esa-container | .astro | Centered, max-width layout wrapper with a symmetric side gutter. The single place the kit owns "constrain page content to a readable width." (Promoted from cb-fish's cbf-container; esa-app-bar alread… | maxWidth? |
Forms
| Component | Kind | What it is | Props |
|---|---|---|---|
Text Field esa-text-field | web component | The two composites a control needs at each step of the size ramp. A control renders TWO text treatments at one size: the label is UI text (label-*, medium) and the value the user typed is prose (body… | interactive (Lit) |
Textarea esa-textarea | web component | The label and value composites at each step of the control ramp. See the FORMS header in component-tokens.css for why the letters do not line up. | interactive (Lit) |
Select esa-select | web component | Label / trigger text is UI text (label-*, medium); typed values, options and chips are prose (body-*, regular). See the FORMS header in component-tokens.css. | interactive (Lit) |
Combobox esa-combobox | web component | Label / trigger text is UI text (label-*, medium); typed values, options and chips are prose (body-*, regular). See the FORMS header in component-tokens.css. | interactive (Lit) |
Input Tag esa-input-tag | web component | Label / trigger text is UI text (label-*, medium); typed values, options and chips are prose (body-*, regular). See the FORMS header in component-tokens.css. | interactive (Lit) |
Checkbox esa-checkbox | web component | A choice label is the option's own text, not the group's heading — prose weight, so it reads body-* rather than label-*. See the FORMS header in component-tokens.css for the step→rung mapping. | interactive (Lit) |
Checkbox Group esa-checkbox-group | web component | The group heading is UI text (label-*, medium); each option's own text is prose (body-*, regular). See the FORMS header in component-tokens.css for the mapping. | interactive (Lit) |
Radio Group esa-radio-group | web component | The group heading is UI text (label-*, medium); each option's own text is prose (body-*, regular). See the FORMS header in component-tokens.css for the mapping. | interactive (Lit) |
Switch Toggle esa-switch-toggle | web component | Why a Web Component (not .astro): this needs real behavior — toggle, keyboard, form participation. As a custom element it works in ANY stack (Astro, React, Angular, plain HTML), which is the portable… | interactive (Lit) |
Form Field esa-form-field | .astro | Faithful translation of the Angular esa-form-field: label row + control slot + hint/error text. Error text replaces help text when present. | label? size? helpText? errorText? required? disabled? |
Field Error esa-field-error | .astro | Beacon's ui-field-error binds to an Angular AbstractControl and renders its validation errors when the control is invalid + touched/dirty. That control plumbing is framework-specific, so this is the… | message? icon? id? |
Error Summary esa-error-summary | web component | id of the field to send the user to — the HOST element (<esa-text-field id="email">), not anything inside its shadow root. IDREFs do not cross a shadow boundary in any engine, so the summary cannot p… | interactive (Lit) |
Date Picker esa-date-picker | web component | Label is UI text (medium); the typed date is prose (regular). See the FORMS header in component-tokens.css for the step→rung mapping. | interactive (Lit) |
Color Picker esa-color-picker | web component | The label is UI text. The hex field is the one value slot in the kit set in the MONO face — a hex code is tabular, so it reads code-* rather than body-*. | interactive (Lit) |
Range Slider esa-range-slider | web component | Both slots are UI text at medium: the field label, and the numeric readout — a readout is chrome, not something the user typed, so it stays label-*. | interactive (Lit) |
File Upload esa-file-upload | web component | Faithful translation of the Angular esa-file-upload: - signal inputs → Lit reactive properties - filesSelected output → bubbling/composed 'change' CustomEvent (detail.files) - host dragging/disabled… | interactive (Lit) |
File List esa-file-list | web component | File name shown in the row. | interactive (Lit) |
Display
| Component | Kind | What it is | Props |
|---|---|---|---|
Avatar esa-avatar | .astro | Faithful translation of the Angular esa-avatar: image → initials → icon fallback, deterministic hue from the name hash, circle/square shapes and size variants. Angular host classes → class list; @if/… | name? src? icon? size? shape? initials? |
Badge esa-badge | .astro | Faithful translation of the Angular esa-badge: same variants, sizes, dot mode, same private --_* tokens reading public semantic tokens with literal fallbacks. Angular host classes → class list here;… | value? variant? size? dot? label? |
Card esa-card | .astro | Faithful translation of the Angular esa-card: variant / headerVariant / padding host classes, header (icon + title + subtitle), body and optional footer. Angular TemplateRef inputs (header/actions/fo… | title? meta? subtitle? icon? variant? headerVariant? padding? |
Chip Group esa-chip-group | web component | Chip text is UI text at the SEMIBOLD tier. It rendered font-weight: 600 as a raw literal — 600 is not a token weight in this system (semibold is 550), so adopting the composite is a small deliberate… | interactive (Lit) |
Alert Box esa-alert-box | .astro | Faithful translation of the Angular esa-alert-box: info/success/warning/danger variants with auto-mapped Lucide icons, optional title, slotted message, and an optional dismiss button. Angular host cl… | variant? title? dismissable? live? |
Danger Zone esa-danger-zone | .astro | Faithful translation of Beacon's ui-danger-zone: a bordered section that corrals destructive action(s) behind clear danger-colored chrome so a misclick isn't a zero-effort accident. Angular heading/d… | heading? description? |
Pill esa-pill | .astro | Faithful translation of the Angular esa-pill: required label, color variants, size variants, optional leading Lucide icon, and an optional remove button. Angular host classes → class list; @if → cond… | label variant? removable? size? category? shape? |
Pillbox esa-pillbox | .astro | Faithful translation of the Angular esa-pillbox: a flex-wrap container that lays out pills with a configurable gap. Angular host class bindings on gap() become a class string here; <ng-content> becom… | gap? |
Progress Bar esa-progress-bar | .astro | Faithful translation of the Angular esa-progress-bar: determinate/indeterminate modes, size and color variants, optional label + percentage value, and the clamped 0–100 fill. Angular host classes/ari… | value? mode? size? variant? label? showValue? |
Loading Spinner esa-loading-spinner | .astro | Faithful translation of the Angular esa-loading-spinner: xs/sm/md/lg sizes and an optional custom color (CSS value, defaults to --color-background-brand). Angular host classes + [style.--_spinner-col… | size? color? label? decorative? |
Loading Overlay esa-loading-overlay | .astro | Faithful translation of the Angular esa-loading-overlay: covers its positioned parent with a spinner (lg) and an optional message when active; transparent switches the opaque backdrop to a semi-trans… | active? message? transparent? |
Empty State esa-empty-state | .astro | Faithful translation of the Angular esa-empty-state: optional icon, required title, optional description, slotted actions, and xs/sm/md/lg size variants. Angular host classes → class list; @if → cond… | title description? size? |
Back To Top esa-back-to-top | web component | Why a Web Component (not .astro): it owns runtime behavior — a passive scroll listener that shows/hides the button past a threshold, and click-to-scroll-to-top. As a custom element it works in any st… | interactive (Lit) |
Collapsible esa-collapsible | .astro | A single disclosure section: an icon + title summary over a slotted body, built on the native <details>/<summary> element (free a11y, keyboard, and open/close state — no JS). The standard disclosure… | title icon? iconPaths? open? flush? |
Keycap esa-kbd | .astro | A keycap for rendering keyboard hints (/, Tab, Esc, ↑ ↓ ↵). Slot the key label. | — |
Overlays
| Component | Kind | What it is | Props |
|---|---|---|---|
Dialog esa-dialog | web component | modal dialog [wc]. Built on the NATIVE <dialog> element, opened with showModal(). | interactive (Lit) |
Confirm Dialog esa-confirm-dialog | web component | confirmation modal [wc]. Faithful translation of the Angular esa-confirm-dialog. | interactive (Lit) |
Side Dialog esa-side-dialog | web component | a slide-in drawer / side sheet (Ecology's first). Aligned to Beacon's ui-side-dialog. | interactive (Lit) |
Popover esa-popover | web component | click/hover anchored popover [wc]. Faithful translation of the Angular esaPopover directive + popover content component (which used @angular/cdk/overlay). | interactive (Lit) |
Tooltip esa-tooltip | web component | hover/focus tooltip [wc]. Faithful translation of the Angular esaTooltip directive + tooltip panel (which used @angular/cdk/overlay). | interactive (Lit) |
Dropdown Menu esa-dropdown-menu | web component | click-toggled menu [wc]. Faithful translation of the Angular esa-dropdown-menu (which used @angular/cdk/overlay CdkConnectedOverlay). | interactive (Lit) |
Command Palette esa-command-palette | web component | The command's name, as it reads in the list. e.g. | interactive (Lit) |
Entity Search esa-entity-search | web component | A facet/scope the search can be narrowed to (e.g. Projects, People, Funds). | interactive (Lit) |
Snackbar esa-snackbar-container | web component | Milliseconds before the toast dismisses itself. **0 (the default) means it stays until dismissed.** This default changed on 2026-08-16, from 5000. | interactive (Lit) |
Snackbar Item esa-snackbar-item | web component | a single toast [wc]. Faithful translation of the Angular esa-snackbar-item. | interactive (Lit) |
Search Panel esa-search-panel | web component | Faithful translation of the Angular esa-search-panel (overlays entry point): - Angular signal inputs (placeholder/results/loading/position) → Lit properties - two-way open model → reflected open attr… | interactive (Lit) |
Navigation
| Component | Kind | What it is | Props |
|---|---|---|---|
App Bar esa-app-bar | .astro | The full-bleed horizontal chrome shell shared by top nav bars, sub-bars, and footers. It sets a COLOR CONTEXT (background + currentColor) from ecology semantic tokens via tone, then exposes three slo… | tone? contained? maxWidth? as? ariaLabel? class? |
Nav Dropdown esa-nav-dropdown | .astro | A chrome-button trigger paired with a floating panel, using a native <details>/<summary> disclosure — zero runtime JS, same pattern as esa-header-nav. The trigger reuses esa-button (variant="chrome"… | label icon? size? align? |
Link Column esa-link-column | .astro | A footer/sitemap column: heading + thin rule + a list of links. Inherits currentColor (the rule is derived from it), so it reads on a brand footer or a light surface without carrying brand values. | heading href? links |
Header Nav esa-header-nav | .astro | A data-driven convenience SET, now composed from the chrome bricks rather than re-implementing them: esa-app-bar → the bar shell + start/main/end slots + tone esa-icon-link → plain nav links esa-nav-… | items? user? navLabel? |
Sidebar Nav esa-sidebar-nav | web component | Why a Web Component (not .astro): the sidebar carries real runtime state — a collapse toggle (icon-rail vs. full width) and per-parent accordion expand. | interactive (Lit) |
Breadcrumbs esa-breadcrumbs | .astro | Faithful translation of the Angular esa-breadcrumbs: same item shape, size variants, separator icon, and "last item = current page" semantics. Angular host classes → class list; Angular @for/@if → JS… | items size? |
Pagination esa-pagination | web component | Why a Web Component (not .astro): page navigation is pure runtime state — current page, prev/next/first/last, page-size selection, and the derived "1 – 25 of 100" range label. Not a form control (no… | interactive (Lit) |
Tab Layout esa-tab-layout | web component | The two composites a tab renders at each step of the size ramp. A tab label is regular until it is the selected one, and then it is UI text carrying state — so the active row swaps family rather than… | interactive (Lit) |
Filters
| Component | Kind | What it is | Props |
|---|---|---|---|
Filter Container esa-filter-container | .astro | Faithful translation of the Angular esa-filter-container: a wrapping flex row that lays out filter dropdowns, pills, and the clear button with consistent wrap + gap. In Angular this also provided the… | gap? rowGap? |
Filter Dropdown esa-filter-dropdown | web component | The three composites this control renders at each step of the size ramp. The trigger is UI text (label-*, medium) and gains weight — not size — once a filter is applied, so selection reads as emphasi… | interactive (Lit) |
Filter Pills esa-filter-pills | .astro | Faithful translation of the Angular esa-filter-pills: rounded chips showing "<label>: <displayValue>" with an x remove button. In Angular the chips came from the injected EsaFilterService. | filters? |
Filter Clear Button esa-filter-clear-button | .astro | Faithful translation of the Angular esa-filter-clear-button: same ghost/link styling, optional leading icon (Lucide filter-x), and "Clear all" default label. In Angular, visibility was driven by the… | label? showIcon? hidden? |
Data & Editors
| Component | Kind | What it is | Props |
|---|---|---|---|
Chart esa-chart | web component | an accessibility-corrected wrapper over AG Charts Community. WHY A WRAPPER. | interactive (Lit) |
Data Grid esa-grid | reference | esa-grid is a thin Ecology skin over AG Grid (ag-grid-angular / ag-grid-community). wraps AG Grid | — |
Map esa-map | reference | esa-map renders an interactive slippy map with markers, or a themed placeholder when the mapping library is absent. wraps Leaflet | — |
Rich Text Editor esa-rich-text-editor | reference | esa-rich-text-editor is a WYSIWYG field: a formatting toolbar above an editable content area, wired as a form control. wraps TinyMCE | — |
Deprecated
Still shipped, still working — each is a shim that forwards to its replacement and warns
at build time, so a spoke that upgrades does not break. They are listed here rather than
in the group they used to sit in so nobody picks one by browsing. Migrate a spoke with
/update-tokens.
| Component | Kind | What it is | Props |
|---|---|---|---|
Icon Link esa-icon-link | .astro | use esa-button variant="chrome" DEPRECATED (2026-08-14). Now a shim over esa-button. | href? icon? iconRight? trailing? size? active? weight? type? tag? |
Icon Button esa-icon-button | .astro | use esa-button variant="chrome" iconOnly DEPRECATED (2026-08-14). Now a shim over esa-button. | icon label href? size? type? |
A composition you keep rebuilding that isn't a single lego? It may belong in the Pattern Library — or be a /request-lego. The on-disk catalog is always the source of truth: ls node_modules/@esa/ecology/src/components/ from any spoke.