Filter row
Use a filter row when a page lets readers narrow a dataset without leaving the page. It belongs immediately before the table, list, or grouped dataset it controls, after any introductory prose, sources, or changelog.
| Colour | Foundations |
| Typography | Foundations |
| Breadcrumbs | Components |
| Cards | Components |
When to use#
- The page lets readers narrow a dataset without leaving the page; place the row immediately before the table, list, or grouped dataset it controls, after any introductory prose, sources, or changelog
- Filter rows are interactive controls, not metadata — do not use metadata tag classes for them; filter chips change visible rows, metadata tags only describe content
- Always use the shared partial so the spacing, button classes, count styling, and optional horizontal overflow wrapper stay consistent
- Use a reset button when only one filtered table is shown and the page has an explicit all-state; omit it when filters are additive chips for cards, grouped lists, or sections where the unfiltered state is simply no chip selected
- Not for jumping to sections — an anchor index moves the reader, a filter row changes what is visible
- Current users: NANP telephony, talks archive, publications, recommendations, and recognition
Implementation#
{{ partial "data-page/filter-row.html" (dict
"wrapClass" "overflow-x-auto pb-1"
"class" "filter-chip-list flex-nowrap"
"ariaLabel" "Filter by topic"
"reset" (dict "label" (i18n "all") "count" $total "attrs" "data-table-filter-reset" "countAttrs" "data-table-visible-count" "active" true)
"items" $filterItems
) }}Each item provides label, count, and the data attributes required by the page behaviour:
dict "label" "Security" "count" 12 "attrs" "data-table-filter-group=\"tag\" data-table-filter-value=\"security\""<nav class="filter-chip-list" aria-label="Filter by topic">
<button class="filter-chip filter-chip-button tag-pill-active" type="button" data-table-filter-reset aria-pressed="true">All <span class="filter-chip-count" data-table-visible-count aria-live="polite" aria-atomic="true">34</span></button>
<button class="filter-chip filter-chip-button" type="button" data-table-filter-group="tag" data-table-filter-value="security" aria-pressed="false">Security <span class="filter-chip-count">12</span></button>
</nav>The partial renders markup only; behaviour comes from whichever page script recognizes the data attributes passed through attrs and navAttrs. Three behaviours exist in assets/js/site.js:
initTableLists(pages with adata-table-listcontainer): chips usedata-table-filter-groupanddata-table-filter-value, the reset usesdata-table-filter-reset, the visible count usesdata-table-visible-countinitTalksArchive(talks archive): chips usedata-talks-filter-groupanddata-talks-filter-value, the reset usesdata-filter-reset, the count usesdata-talks-visible-count- The recommendation filter block (
navAttrsset todata-recommendation-filters): chips usedata-filter-groupanddata-filter-value— recommendations, recognition, and NANP telephony
The Hugo partial is layouts/partials/data-page/filter-row.html. It renders the <nav> and its chips — buttons with aria-pressed, or links when an item carries href — and nothing else; wiring the chips to rows is the host page’s job. The chip styling is the filter-chip-* classes in assets/css/site.css.
Options#
| Option | Purpose |
|---|---|
items | List of chip dicts: label, count, attrs, countAttrs, and href to render a link instead of a button |
reset | Dict for the leading all-state chip: label, count, attrs, countAttrs, active, href |
ariaLabel / ariaLabelKey | Accessible label for the <nav>, literal or resolved through i18n |
class | Classes on the <nav> (default filter-chip-list) |
navAttrs | Extra attributes on the <nav> |
wrapClass | When set, wraps the <nav> in a div with these classes, usually for horizontal overflow |
buttonClass | Chip classes (default filter-chip filter-chip-button) |
Interface manifest
- Kind
- Component
- Category
- Data
- Status
- Implemented
- Implementation
- Partial:
layouts/partials/data-page/filter-row.htmlCSS:assets/css/site.cssJavaScript:assets/js/site.js
Accessibility#
- The row is a
<nav>named byariaLabelorariaLabelKey; always pass one, because the partial renders the attribute verbatim and an omitted label ships an unnamed landmark witharia-label="" - Chips are native
<button type="button">elements carryingaria-pressed; the page behaviour toggles it together with thetag-pill-activeclass, and the reset chip staysaria-pressed="true"while no filter is selected - Tab moves between chips and Enter or Space toggles one — native button behaviour, with no custom key handling
- The count in the reset chip carries
aria-live="polite"andaria-atomic="true", so screen readers hear the new visible count after a filter changes it, not just see the number change; a page-specific empty-state message uses the same pattern - Avoid a link chip (
href) for a filter that toggles in place — the partial renders links withoutaria-pressed, and a link announces navigation