GitHub

Entity Search

A scoped entity-search overlay — a sibling to the command palette, but for navigating to records rather than firing actions. Set entities + scopes; it filters client-side, shows per-scope counts, highlights matches, groups by scope, and emits events the consumer handles.

Stable wc import '@esa/ecology/esa-entity-search';

Preview

Data is set as properties in a script. Open with the button or /. Try a query (e.g. “ri”) to see counts + highlighting; Tab cycles scopes; ⌘/Ctrl + Enter fires show-all.

<button id="open-es">Open entity search</button>

<esa-entity-search id="es" hotkey="slash" placeholder="Search projects, people, documents…"></esa-entity-search>

API

PropTypeDefaultDescription
entities EsaSearchEntity[] [] The searchable records, set as a property. Each: { id, title, subtitle?, scope, icon?, url?, meta? }. Filtered client-side.
scopes EsaSearchScope[] [] Facets to narrow by. Each: { id, label, icon? }. An implicit "All" facet is prepended.
recent EsaSearchEntity[] [] Shown when the query is empty and the "All" facet is active.
rowActions EsaSearchRowAction[] [] Per-row secondary actions (e.g. Impersonate). Each: { id, label, icon?, scopes? }. scopes restricts which rows show it.
open boolean false Reflected open state.
placeholder string 'Search…' Input placeholder.
allLabel string 'All' Label for the implicit all-scopes facet.
hotkey '' | 'mod+k' | 'slash' '' Built-in open shortcut. 'mod+k' = Cmd/Ctrl+K toggle; 'slash' = '/' opens (ignored while typing in a field).

Events

EventTypeDefaultDescription
select { entity } A row was chosen (click or Enter). The consumer navigates (e.g. to entity.url).
scope-change { scope } The active facet changed. scope is '' for All.
show-all { query, scope } Cmd/Ctrl+Enter — "see all results". The consumer routes to a full results page.
row-action { action, entity } A per-row action button was clicked. action is the EsaSearchRowAction id.

Methods

PropTypeDefaultDescription
show() method Opens, clears the query + scope, focuses the input.
close() method Closes the overlay.
toggle() method Toggles open state.

Accessibility

  • The overlay is role="dialog"; results are role="listbox" / role="option" with aria-selected; facets are a role="tablist".
  • ArrowUp / ArrowDown move the active row (wrapping across groups), Enter selects, Esc closes, Tab / Shift+Tab cycle facets.
  • The input is focused automatically on open.

Theming surface

Every public token this component reads, extracted from its source at build time. 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.

TokenTierResolves to
--color-primary-contrast component #fff
--entity-search-bg component #fcfcfc via --color-surface-elevated--color-gray-1
--entity-search-border-color component #cecece via --color-border--color-gray-7
--entity-search-max-height component 70vh
--entity-search-radius component 0.75rem via --radius-400
--entity-search-row-bg-active component #f0f0f0 via --color-surface-sunken--color-gray-3
--entity-search-shadow component 0 20px 60px rgba(0, 0, 0, 0.2)
--entity-search-width component 600px
--color-backdrop semantic rgba(0, 0, 0, 0.5) via --color-black-a-7
--color-border semantic #cecece via --color-gray-7
--color-border-light semantic #d9d9d9 via --color-gray-6
--color-primary semantic #46a758 via --color-grass-9
--color-primary-border semantic #b2ddb5 via --color-grass-6
--color-surface semantic #fcfcfc via --color-gray-1
--color-text-muted semantic #838383 via --color-gray-10
--color-text-primary semantic #202020 via --color-gray-12
--color-text-secondary semantic #646464 via --color-gray-11
--font-sans semantic 'DM Sans', sans-serif
--type-size-100 semantic clamp(0.625rem, 0.56rem + 0.32vw, 0.75rem)
--type-size-200 semantic clamp(0.75rem, 0.66rem + 0.44vw, 0.9375rem)
--type-size-300 semantic clamp(0.875rem, 0.77rem + 0.52vw, 1.125rem)
--font-weight-medium primitive 500
--font-weight-semibold primitive 550
--radius-200 primitive 0.5rem
--radius-full primitive 9999px
--spacing-100 primitive 0.25rem
--spacing-150 primitive 0.375rem
--spacing-200 primitive 0.5rem
--spacing-250 primitive 0.625rem
--spacing-300 primitive 0.75rem
--spacing-400 primitive 1rem
--spacing-600 primitive 2rem
--spacing-700 primitive 3rem
--z-modal primitive 400
--z-modal-backdrop primitive 300