Filterable collection

Task#

Use this pattern when readers need to scan a bounded collection and narrow it by values already present in the data. It is used for publications, the talks archive, and recommendations. It is not a site search: filtering acts on an already-rendered, known collection rather than an index of every page.

Composition#

The page starts with the standard Page header. A Filter row is optional: use it only when it meaningfully narrows the collection. Results use a Data table when readers compare columns, or a semantic list when entries are narrative. Pagination is added only when the chosen result model needs it.

Content and data#

Keep the dataset as the authority. Filter keys must be stable values in that data, while visible labels may be localized or derived by the layout. Each dataset needs a deliberate result shape: publications are comparable rows, talks are sortable archival records, and recommendations are individual quotations. Do not force all three into the same card or table markup.

Responsive behaviour#

Filter controls wrap or scroll horizontally according to their documented filter-row variant. Tables keep their minimum readable width inside the shared scroll region; narrative results remain a single vertical list. Filtering and client-side paging preserve the page’s reading flow at every width rather than replacing results with a separate mobile interface.

Implementation#

The page layout derives filter items and result rows from one data file, then passes the controls to data-page/filter-row.html. Publications use data-table-* attributes with sortable rows and data-page/table-pagination.html; the talks archive has an older, equivalent data-talks-* controller; recommendations filter a semantic list. The shared CSS supplies the visual states, and assets/js/site.js changes only the currently visible results.

Pattern manifest

Kind
Pattern
Category
Collection
Status
Implemented
Content and data
one structured data source with stable filter values and visible labelsa result presentation chosen by the data: table for comparison, list for narrative entriesan explicit empty state whenever a filter can hide every result
Accessibility
native buttons for filters with a named filter navigation landmarkan announced result count or empty state after a filter changes visibilitynative table or list semantics retained while results are filtered, sorted, or paged
Implementation
Partial:layouts/partials/entry-title-block.htmllayouts/partials/data-page/filter-row.htmllayouts/partials/data-page/table-wrap.htmllayouts/partials/data-page/table-pagination.htmlLayout:layouts/publications/publications.htmllayouts/talks/archive.htmllayouts/about/recommendations.htmlData:data/publications.ymldata/talks.ymldata/recommendations.ymlCSS:assets/css/site.cssJavaScript:assets/js/site.js
Related patterns
Reference index

Accessibility#

  • The filter row is a named navigation landmark containing native buttons. An active state is exposed with the component’s documented ARIA behaviour; colour is never the only signal.
  • A filter update announces either the visible result count or the empty state through a polite live region. Do not replace the whole results region without a status message.
  • Tables keep their headers, scopes, and scroll-region name. List implementations retain <ol> or <ul> and <li> semantics instead of simulating a list with generic containers.
  • Sorting controls are real buttons with an exposed sort direction. Pagination uses native links or buttons and announces the currently visible range.
  • Use this pattern only for a known, bounded dataset. For global content discovery, use Search; for jumps to repeated sections already visible on a page, use the Reference index.