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): - color: primary | secondary | danger | success | warning | info | ai | ghost - appearance: fill | outline | dashed | soft… | color? appearance? active? size? disabled? loading? icon? iconOnly? type? href? target? rel? class? |
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 | Optional leading icon: the inner Lucide SVG markup (the <path>/<rect>… children, no <svg> wrapper) — the same paths convention as esa-icon. Inherits currentColor, so it flips to the inverse color whe… | 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? |
Icon Link esa-icon-link | .astro | The atomic nav / menu link: [leading icon] label [trailing affordance]. INHERITS currentColor, so it sits on any surface (dark chrome or light content) without knowing the brand — the containing esa-… | href? icon? trailing? size? active? weight? type? tag? |
Icon Button esa-icon-button | .astro | Icon-only action for toolbars and chrome (search, close, overflow, etc.). Lightweight + transparent and INHERITS currentColor, so it lives happily on a dark app bar or a light surface. | icon label href? size? type? |
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 (at the page-title role by default, or the oversized display role via prominence="displ… | title lede? eyebrow? icon? prominence? as? |
Stat esa-stat | .astro | A big display value, a readable label, and an optional muted sub/caption. 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 | Faithful translation of the Angular esa-text-field (a ControlValueAccessor that composed esa-form-field around a native <input>). Here the field chrome (label / help / error) is rendered inline so th… | interactive (Lit) |
Textarea esa-textarea | web component | Faithful translation of the Angular esa-textarea (a ControlValueAccessor that composed esa-form-field around a native <textarea>, with optional auto-resize). Field chrome (label / help / error) is re… | interactive (Lit) |
Select esa-select | web component | Faithful translation of the Angular esa-select: - signal inputs → Lit reactive properties - ControlValueAccessor (NG_VALUE) → form-associated element + ElementInternals - host size class → reflected… | interactive (Lit) |
Combobox esa-combobox | web component | Faithful translation of the Angular esa-combobox: - signal inputs → Lit reactive properties - ControlValueAccessor (NG_VALUE) → form-associated element + ElementInternals - host size class → reflecte… | interactive (Lit) |
Input Tag esa-input-tag | web component | Faithful translation of the Angular/Beacon ui-input-tag: - signal inputs → Lit reactive properties - ControlValueAccessor (NG_VALUE) → form-associated element + ElementInternals - host size class → r… | interactive (Lit) |
Checkbox esa-checkbox | web component | Faithful translation of the Angular esa-checkbox (a ControlValueAccessor with a custom box, hidden native input, indeterminate state, and Space/Enter keyboard toggling). The lucide-angular check/minu… | interactive (Lit) |
Checkbox Group esa-checkbox-group | web component | Faithful translation of the Angular esa-checkbox-group (a ControlValueAccessor whose value is a string[] of selected option values, with vertical/horizontal orientation and per-option disabled state)… | interactive (Lit) |
Radio Group esa-radio-group | web component | Faithful translation of the Angular esa-radio-group (a ControlValueAccessor whose value is the single selected option value, with vertical/horizontal orientation, per-option disabled state, and a cus… | 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? |
Date Picker esa-date-picker | web component | Faithful translation of the Angular esa-date-picker: - signal inputs → Lit reactive properties - ControlValueAccessor (NG_VALUE) → form-associated element + ElementInternals - host size class → refle… | interactive (Lit) |
Color Picker esa-color-picker | web component | Faithful translation of the Angular esa-color-picker: - signal inputs → Lit reactive properties - ControlValueAccessor (NG_VALUE) → form-associated element + ElementInternals - host size/disabled cla… | interactive (Lit) |
Range Slider esa-range-slider | web component | Faithful translation of the Angular esa-range-slider: - signal inputs → Lit reactive properties - ControlValueAccessor (NG_VALUE) → form-associated element + ElementInternals - host size/disabled cla… | 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? |
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? |
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? subtitle? icon? variant? headerVariant? padding? |
Chip Group esa-chip-group | web component | Active-state palette for a chip. Maps to Ecology semantic tokens inside the primitive. | 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? |
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? |
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-primary). Angular host classes + [style.--_spinner-color] → cla… | size? color? |
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]. Faithful translation of the Angular esa-dialog (which used @angular/cdk/dialog for the overlay/backdrop/focus-trap). | 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 | filterable command overlay [wc]. Faithful translation of the Angular esa-command-palette. | 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 | toast stack with auto-dismiss [wc]. Faithful translation of the Angular esa-snackbar-container + EsaSnackbarService. | 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? class? |
Nav Dropdown esa-nav-dropdown | .astro | An icon-link 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-icon-link (tag="summary"); t… | 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? |
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 | Why a Web Component (not .astro): tabs are the canonical ARIA tablist pattern — active-tab state, roving keyboard navigation (Arrow/Home/End), and a panel that swaps with the active tab. All runtime… | 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 | Why a Web Component (not .astro): real behavior — open/close panel, search, keyboard navigation (Arrow/Enter/Escape), single + multi select, and overlay positioning. As a custom element it works in a… | 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 |
|---|---|---|---|
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 | — |
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.