@arraypress/filter-toolbar-astro
v1.1.0
Published
Astro listing toolbar — sort + grid/list view toggle + results count, with a client-side filter/sort/paginate runtime (paged, load-more, infinite).
Downloads
360
Maintainers
Readme
@arraypress/filter-toolbar-astro
Astro listing toolbar — sort + grid/list view toggle + results count, with a client-side filter / sort / paginate runtime (paged, load-more, or infinite-scroll).
Install
npm install @arraypress/filter-toolbar-astroUse
---
import { FilterToolbar } from '@arraypress/filter-toolbar-astro';
---
<FilterToolbar resultsCount={products.length} />
<div id="product-grid" class="fb-grid fb-grid--grid">
{products.map((p) => <ProductCard product={p} />)}
</div>
<script>
import { initFilterToolbar } from '@arraypress/filter-toolbar-astro/runtime';
document.addEventListener('astro:page-load', () => {
initFilterToolbar({
pageSize: 24,
currencySymbol: '£',
paginationMode: 'paged', // | 'load-more' | 'infinite'
});
});
</script>DOM contract
Cards need data attributes the runtime reads. These are the keys sort/filter logic looks at:
<article
class="product-card"
data-category="bundles"
data-price="49.99"
data-order="3"
data-title="Future Bass Vol. 1"
data-date="2026-04-12"
>
…
</article>The toolbar component covers:
#open-filters— drawer trigger (with#active-filter-countbadge)#results-count— live count label#sort-select— sort dropdown#view-grid/#view-list— view toggle
You provide the rest of the markup the runtime expects, with these default ids/classes:
| Surface | Default selector | Purpose |
|---------------------|------------------------------|--------------------------------|
| Grid container | #product-grid | Wrapper for .product-cards |
| Category chips | .chip[data-filter="…"] | Buttons that filter by category|
| Filter drawer | #filter-drawer | Slide-in drawer body |
| Backdrop | #filter-backdrop | Click-to-close |
| Drawer close btn | #close-filters | |
| Drawer apply btn | #apply-filters | |
| Drawer clear btn | #clear-filters | |
| Empty state | #empty-state | Shown when no cards match |
| Price slider | #price-max + #price-max-value | |
| Paged controls | #pagination, #pagination-pages, #page-prev, #page-next | |
| Load-more button | #load-more | |
| Infinite sentinel | #scroll-sentinel | |
Override any of these via selectors if your markup uses different
ids.
Pagination modes
'paged'(default) — numbered prev/next + page buttons.'load-more'— "Show more" button reveals the next chunk on click.'infinite'— auto-reveals chunks as#scroll-sentinelenters the viewport (300px rootMargin).
Sort modes
Five built-ins, sorted by reading these card attributes:
| Mode | Read from |
|--------------|-------------------|
| featured | data-order (asc) |
| newest | data-date (desc) |
| price-asc | data-price (asc) |
| price-desc | data-price (desc)|
| name | data-title (locale-aware A→Z) |
Toolbar props
| Prop | Default | Description |
|-----------------------|-----------------------|------------------------------------------------------------|
| resultsCount | '' | Initial server-rendered count. Runtime updates it. |
| sortOptions | DEFAULT_SORT_OPTIONS| Custom sort dropdown options. |
| showFiltersTrigger | true | Render the Filters button. |
| filtersLabel | 'Filters' | |
| resultsLabel | 'results' | |
| showViewToggle | true | Render the grid/list toggle. |
| sortAriaLabel | 'Sort products' | aria-label for the <select>. |
| class | — | Extra classes on the toolbar root. |
Runtime options
initFilterToolbar({
pageSize: 24, // required
currencySymbol: '£', // for the price-slider label
defaultSort: 'featured',
paginationMode: 'paged',
loadMoreLabel: 'Show more',
viewStorageKey: 'ap-view-mode',
gridClass: 'fb-grid--grid',
listClass: 'fb-grid--list',
cardSelector: '.product-card',
attributeFacets: [ /* optional multi-select facets — see below */ ],
selectors: { /* override any of the default ids */ },
});Idempotent — calling twice on the same #product-grid is a no-op.
Safe to fire from both DOMContentLoaded and astro:page-load.
Attribute facets
Beyond the single category chip + price slider, you can layer any number
of multi-select attribute facets (genre, format, synth, tag, …) via
attributeFacets. Each facet reads a delimited token list off a card
data attribute and shows a card only if — for every facet with an active
selection — the card carries at least one selected token (OR within a
facet, AND across facets, AND with category + price).
Card markup — emit space- or comma-separated tokens (use slugs, no internal spaces):
<article class="product-card"
data-category="pack"
data-genre="uplifting-trance progressive-trance"
data-format="presets midi">…</article>Facet chips — each carries data-value; a data-value="" or
data-value="all" chip clears that facet:
<button class="facet-genre" data-value="uplifting-trance" aria-pressed="false">Uplifting Trance</button>
<button class="facet-genre" data-value="progressive-trance" aria-pressed="false">Progressive Trance</button>initFilterToolbar({
pageSize: 24,
attributeFacets: [
{ key: 'genre', dataKey: 'genre', chipSelector: '.facet-genre' },
{ key: 'format', dataKey: 'format', chipSelector: '.facet-format', urlParam: true },
],
});| Field | Required | Description |
|----------------|----------|---------------------------------------------------------------------|
| key | yes | Stable unique id (also the URL param name when urlParam). |
| dataKey | yes | Card dataset key — 'genre' reads data-genre. |
| chipSelector | yes | Selector for the facet's chip buttons (each with data-value). |
| urlParam | no | Reflect the selection into the URL as ?key=a,b + restore on load. |
The runtime toggles .active + aria-pressed on chips, folds active
facet values into the #active-filter-count badge, and clears them with
the drawer's #clear-filters button. Omitting attributeFacets leaves
the existing single-facet behaviour completely unchanged.
Deep-linking
?cat=bundles on the URL auto-clicks the matching chip on first
load, so /products?cat=bundles lands users straight on the filtered
view.
Styling
The toolbar ships no styles — it emits class hooks only:
.fb-toolbar
.fb-toolbar-filters, .fb-toolbar-filters-label, .fb-toolbar-active-badge
.fb-toolbar-count, .fb-toolbar-count-num, .fb-toolbar-count-label
.fb-toolbar-right
.fb-toolbar-sort, .fb-toolbar-sort-icon, .fb-toolbar-sort-select
.fb-toolbar-view, .fb-toolbar-view-btn (`.active` when picked)License
MIT
