Filtering Gatsby content by Sanity categories and tags
Creating a client-side filtering system for speakers with categories and tags in your Gatsby + Sanity project is definitely achievable! Here's how to approach this:
The Basic Approach
Since you're building this for a Gatsby site with a conference speaker list, you'll want to implement client-side filtering using React state management. The general pattern is:
- Query all speakers data (including their categories and tags) from Sanity via Gatsby's GraphQL layer
- Store the full dataset in your component
- Track selected filter values (checkboxes) in state
- Filter the displayed results based on selected filters
Getting Your Data from Sanity
First, structure your Sanity schema with categories and tags as references or arrays. Then in your Gatsby page, query the data using Gatsby's GraphQL integration with Sanity:
export const query = graphql`
query {
allSanitySpeaker {
nodes {
id
name
bio
categories {
title
slug
}
tags {
title
slug
}
}
}
}
`Implementing the Filter UI
For the filtering interface (similar to the ffconf example you linked), you'll want to:
- Extract unique categories and tags from your data
- Create checkbox inputs for each filter option
- Track selected filters in component state using
useState - Filter your results based on selections
Here's a basic React pattern using hooks:
const SpeakersPage = ({ data }) => {
const [selectedCategories, setSelectedCategories] = useState([])
const [selectedTags, setSelectedTags] = useState([])
const speakers = data.allSanitySpeaker.nodes
// Filter logic
const filteredSpeakers = speakers.filter(speaker => {
const categoryMatch = selectedCategories.length === 0 ||
speaker.categories.some(cat => selectedCategories.includes(cat.slug))
const tagMatch = selectedTags.length === 0 ||
speaker.tags.some(tag => selectedTags.includes(tag.slug))
return categoryMatch && tagMatch
})
// Render checkboxes and filtered results
}Handling Checkbox State
Based on this helpful example from the Sanity community (which applies to Gatsby too since it's React-based), you can manage checkbox state like this:
const handleCategoryChange = (slug) => {
setSelectedCategories(prev =>
prev.includes(slug)
? prev.filter(s => s !== slug)
: [...prev, slug]
)
}There's also a CodeSandbox demo showing checkbox filtering that demonstrates the fundamentals perfectly.
Key Implementation Tips
Checkbox State Management: Use arrays to track selected filters and toggle them on/off when checkboxes are clicked.
Filter Logic: Decide whether you want AND logic (speaker must match ALL selected filters) or OR logic (speaker matches ANY selected filter). The ffconf example likely uses OR within each filter type (categories OR tags).
Performance: Since this is client-side filtering on a conference speaker list, performance should be fine. All data is already loaded at build time via Gatsby's GraphQL layer, which is one of the key benefits of Gatsby's integration with Sanity.
Clear Filters: Include a "Clear all" or "Reset" button to empty your filter state arrays.
Using Sanity's _id: When mapping over your filtered results, you can use Sanity's _id field as the React key prop since it's guaranteed to be unique.
Why Client-Side vs Server-Side?
For a conference speaker list, client-side filtering gives you instant, smooth interactions without page reloads. Since Gatsby pre-builds everything at build time, all your speaker data is already available in the browser. If you had thousands of speakers, you might consider server-side filtering with GROQ queries, but for a typical conference (dozens to hundreds of speakers), client-side is perfect.
This is essentially building a faceted search interface with checkboxes - a common pattern in directory sites and e-commerce filters. The key is maintaining filter state and using JavaScript's filter() and some() array methods to match against your criteria.
Show original thread6 replies
Sanity β Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.