Quick filters
A horizontal list of buttons used to filter content or results.
Summary
Quick filters help users quickly identify and move between clear groups of content.
They are intended to either replace or work alongside existing filters where there is a meaningful split in content type. They raise important filtering options to a more visible layer of the page, making it easier for users to understand the main groups or themes available to them.
Quick filters should help users access content more quickly, especially when the main content groups are already clearly defined.
Example
<nav
class="tel-quick-filters"
data-component="tel-quick-filters"
data-module="tel-quick-filters"
>
<div class="tel-quick-filters__filter-title">Filter by level</div>
<ul class="tel-quick-filters__list" role="list">
<span class="tel-quick-filters__list-heading">Show:</span>
<li class="tel-quick-filters__list-item">
<a
href="#"
class="tel-quick-filters__button tel-quick-filters__button--active"
role="button"
aria-pressed="true"
data-filter-value="all"
>
<span>All</span>
</a>
</li>
<li class="tel-quick-filters__list-item">
<a
href="#"
class="tel-quick-filters__button"
role="button"
aria-pressed="false"
data-filter-value="beginner"
>
<span>Beginner</span>
</a>
</li>
<li class="tel-quick-filters__list-item">
<a
href="#"
class="tel-quick-filters__button"
role="button"
aria-pressed="false"
data-filter-value="intermediate"
>
<span>Intermediate</span>
</a>
</li>
<li class="tel-quick-filters__list-item">
<a
href="#"
class="tel-quick-filters__button"
role="button"
aria-pressed="false"
data-filter-value="advanced"
>
<span>Advanced</span>
</a>
</li>
</ul>
</nav>
<hr
class="nhsuk-section-break nhsuk-section-break--m nhsuk-section-break--visible"
/>
<div id="demo-results">
<h3 class="nhsuk-heading-s">Courses</h3>
<ul class="nhsuk-list nhsuk-list--border">
<li data-level="beginner">
<strong>Beginner:</strong> Introduction to NHS Standards
</li>
<li data-level="intermediate">
<strong>Intermediate:</strong> Advanced Nunjucks Templating
</li>
<li data-level="beginner">
<strong>Beginner:</strong> HTML & Accessibility Basics
</li>
<li data-level="advanced">
<strong>Advanced:</strong> Developing Design Systems at Scale
</li>
<li data-level="intermediate">
<strong>Intermediate:</strong> JavaScript Event Delegation
</li>
</ul>
<p id="no-results-message" class="nhsuk-body" style="display: none">
No courses found for the selected levels.
</p>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
const filtersContainer = document.querySelector(".tel-quick-filters");
const items = document.querySelectorAll("#demo-results li");
const emptyMessage = document.getElementById("no-results-message");
if (filtersContainer) {
filtersContainer.addEventListener("tel.quick-filters.change", (event) => {
const activeFilters = event.detail.filters;
let visibleCount = 0;
items.forEach((item) => {
const itemLevel = item.dataset.level;
// Logic: Show if 'all' is active OR if the specific level is selected
const shouldShow =
activeFilters.includes("all") || activeFilters.includes(itemLevel);
item.style.display = shouldShow ? "block" : "none";
if (shouldShow) visibleCount++;
});
// Toggle the "No results" message
emptyMessage.style.display = visibleCount === 0 ? "block" : "none";
});
}
});
</script>
Nunjucks macro options
Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text.
Some options are required for the macro to work; these are marked as "Required" in the option description.
If you're using Nunjucks macros in production with "html" options, or ones ending with "html", you must sanitise the HTML to protect against cross-site scripting exploits.
| Name | Type | Required | Description |
|---|---|---|---|
filterTitle |
string | No | Text to display before the filter list to caption or title the content, such as "Filter by level:". |
heading |
string | No | Text to display before the filter buttons, such as "Show" to provide more detail about the expected interaction. |
showAll |
boolean | No | Set to false to hide the default "All" button. Defaults to true. |
allLabel |
string | No | Custom text for the default "All" button. Defaults to "All". |
allHref |
string | No | The URL the "All" button links to if JavaScript is disabled. Defaults to "#". |
activeTags |
array | No | An array of values representing the buttons that should be styled as active on page load (e.g., ['beginner']). If omitted or empty, the "All" button is styled as active by default. |
tags |
array | Yes | An array of tag objects to render as the filter buttons. |
tags[].label |
string | Yes | The text displayed on the individual filter button. |
tags[].value |
string | Yes | The internal value used for filtering (outputs to the data-filter-value attribute). |
tags[].href |
string | No | The URL the individual filter button links to if JavaScript is disabled. Defaults to "#". |
{% from 'tel/components/quick-filters/macro.njk' import telQuickFilters %}
{{ telQuickFilters({
filterTitle: "Filter by level",
heading: "Show:",
tags: [
{ label: "Beginner", value: "beginner" },
{ label: "Intermediate", value: "intermediate" },
{ label: "Advanced", value: "advanced" }
]
}) }}
Where this is currently used
This component is currently being explored or used in:
- pages where users are looking for learning
- pages where users are viewing their learning history
- pages where users may need to apply more than 1 filter
- current Learning Hub platform designs and prototypes
When to use this component
Use the quick filters component when you have a list of items that can be categorised into clear and mutually exclusive groups.
Use quick filters when there is a clear and meaningful split in content.
They are useful when:
- content can be grouped into a small number of clearly defined types
- the main groups or themes are important enough to make visible on the page
- users are likely to benefit from filtering content quickly without opening a larger filter panel
- the filter options help users understand what kind of content is available
- the same page contains different types of content that users may want to move between quickly
For example, quick filters may be useful where users need to filter learning content by broad content type, activity type or completion state.
When not to use
Do not use quick filters when there is no clear split in content type.
They should not be used when:
- the content does not have a small number of meaningful groups
- the filter options would work more like tags than clear content groups
- filtering may hide content that could still be meaningful to the user
- search or autosuggest would be a better way for users to find what they need
- the page only needs a standard search input or search autosuggest pattern
Quick filters should not be added to make a page feel more interactive. If the content split is not meaningful, the filter may make it harder for users to find relevant results.
How it works
Quick filters work as an inclusive filtering component.
At the All level, no filter is applied. This means users can see all available content in the list or results area.
When a user selects a filter item, the page shows items that match that filter.
When a user selects a second filter item, the page includes results from both selected filters. This means the filters broaden the results across the selected groups rather than narrowing the results to only items that match every selected filter.
For example, if a user selects Courses and eLearning, they should see items that are courses, items that are eLearning, or items that match both.
Content guidance
Quick filter labels should be short, clear and easy to scan.
Use labels that describe meaningful content groups. Avoid labels that are too broad, too technical or too similar to each other.
Labels should:
- use plain English
- match the language users expect to see on the page
- describe content types or groups, not internal categories
- be short enough to scan quickly
- avoid duplication with nearby headings or search labels
Do not use quick filters for long lists of tags or highly specific metadata.
Research evidence
What has been seen so far
Quick filters were tested using click tests across several pages. This helped us understand whether users recognised the filters and could use them in the current platform design.
Testing has included:
- users looking for learning
- users looking through their learning history
- users applying multiple filters to a page
- follow-up survey questions after users interacted with the filters
We have observed users interacting with this component in usability tests and click tests.
Confidence level: medium
We have some evidence that users understand and can use quick filters in the contexts tested so far.
However, we need more research before this component can be considered stable. In particular, we need to explore additional use cases across transaction processes and single-page patterns.
Further testing should look at:
- whether users understand that quick filters are inclusive
- whether users expect multiple selected filters to broaden or narrow results
- whether quick filters work well alongside search and other filters
- whether quick filters are still helpful in more complex journeys
- whether quick filters risk hiding useful content in some contexts