GitHub

Filter Pills

Active filters rendered as removable chips. Each chip shows "label: displayValue" and an x button that dispatches a bubbling esa-filter-remove event carrying { name, value }.

Stable .astro import EsaFilterPills from '@esa/ecology/esa-filter-pills.astro';

Preview

Pass the current active filters; each becomes a removable chip.

Status:OpenStatus:In reviewDepartment:Water Quality
<FilterPills filters={[
  { name: 'status', label: 'Status', value: 'open', displayValue: 'Open' },
  { name: 'status', label: 'Status', value: 'review', displayValue: 'In review' },
  { name: 'dept', label: 'Department', value: 'water', displayValue: 'Water Quality' },
]} />

States

A single chip renders inline; with no filters the component renders nothing at all — matching the Angular @if (activeFilters().length > 0) guard.

Priority:High
<FilterPills filters={[
  { name: 'priority', label: 'Priority', value: 'high', displayValue: 'High' },
]} />

<!-- Empty: renders no DOM -->
<FilterPills filters={[]} />

API

PropTypeDefaultDescription
filters ActiveFilter[] [] Active filters to render. Each is { name, label, value, displayValue }. Empty renders no DOM.

Events

PropTypeDefaultDescription
esa-filter-remove { name, value } Bubbling/composed. Fires when a chip's remove button is clicked, identifying which filter to drop.

Accessibility

  • Each chip carries an aria-label of "label: displayValue" so the pairing is announced as one unit.
  • Remove buttons are native <button>s with an explicit "Remove {label} {displayValue}" accessible name.
  • Remove buttons show a visible focus ring via --focus-ring-* tokens.

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
--filter-pill-bg component #e9f6e9 via --color-primary-bg--color-grass-3
--filter-pill-bg-hover component #daf1db via --color-primary-bg-hover--color-grass-4
--filter-pill-font-size component clamp(0.625rem, 0.56rem + 0.32vw, 0.75rem) via --type-size-100
--filter-pill-label-color component #646464 via --color-text-secondary--color-gray-11
--filter-pill-radius component 9999px via --radius-full
--filter-pill-remove-color component #646464 via --color-text-secondary--color-gray-11
--filter-pill-remove-color-hover component #ce2c31 via --color-danger-strong--color-red-11
--filter-pill-text component #2a7e3b via --color-primary-strong--color-grass-11
--focus-ring-color component #65ba74 via --color-border-focus--color-grass-8
--focus-ring-width component 2px
--font-sans semantic 'DM Sans', sans-serif
--transition-fast semantic 150ms ease
--font-weight-medium primitive 500
--radius-full primitive 9999px
--spacing-050 primitive 0.125rem
--spacing-100 primitive 0.25rem
--spacing-200 primitive 0.5rem
--spacing-300 primitive 0.75rem