Skip to content

Instantly share code, notes, and snippets.

@MattMcAdams
Created March 4, 2022 03:21
Show Gist options
  • Save MattMcAdams/41220c816e6e353693a06a9436c0add4 to your computer and use it in GitHub Desktop.
Save MattMcAdams/41220c816e6e353693a06a9436c0add4 to your computer and use it in GitHub Desktop.
Filter items by tag with JS
body { font-family: sans-serif; max-width: 1300px; margin: 5rem auto; padding: 0 1rem; }
h1, h2, h3, ul, p { margin: 0 0 1rem 0; }
[hidden] { display: none !important; }
.item-list {
margin: 2.5rem 0;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(15em, 1fr));
grid-gap: 1rem;
}
.card {
list-style: none;
margin: 0;
padding: 1rem;
background: #f7f9fb;
border: 1px solid #d7dce0;
}
.tags {
margin: 0;
padding: 0;
display: flex;
gap: 1rem;
}
.tags li {
padding: 0.5rem 1rem;
background: #d7dce0;
list-style: none;
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none; /* hides the native UI */
width: calc(25% - 1rem);
border: 1px solid #d7dce0;
background: white;
padding: 0.5rem 2rem 0.5rem 1rem;
display: block;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8" fill="none" stroke="black"><path d="M7.5 3L4 6 .5 3"/></svg>');
background-size: 0.7em;
background-repeat: no-repeat;
background-position: right 1rem center;
}
label {
display: block;
text-transform: uppercase;
margin: 0 0 1rem;
letter-spacing: 0.1rem;
}
h2 {
text-transform: uppercase;
letter-spacing: 0.1rem;
margin: 5rem 0 2.5rem;
}
<section class="list-section">
<h2>Filterable Item List</h2>
<form>
<label for="filter">Sort by tag</label>
<select name="filter">
<option>All</option>
<option>Example Tag</option>
<option>Test</option>
</select>
</form>
<ul class="item-list">
<li class="card" data-tags="['Example Tag', 'Test']">
<h3>Card Title</h3>
<p>Description</p>
<ul class="tags">
<li>Example Tag</li>
<li>Test</li>
</ul>
</li>
<li class="card" data-tags="['Test']">
<h3>Card Title</h3>
<p>Description</p>
<ul class="tags">
<li>Test</li>
</ul>
</li>
<li class="card" data-tags="['Example Tag', 'Test']">
<h3>Card Title</h3>
<p>Description</p>
<ul class="tags">
<li>Example Tag</li>
<li>Test</li>
</ul>
</li>
<li class="card" data-tags="['Example Tag']">
<h3>Card Title</h3>
<p>Description</p>
<ul class="tags">
<li>Example Tag</li>
</ul>
</li>
</ul>
</section>
<section class="list-section">
<h2>Filterable Item List</h2>
<form>
<label for="filter">Sort by tag</label>
<select name="filter">
<option>All</option>
<option>Example Tag</option>
<option>Test</option>
</select>
</form>
<ul class="item-list">
<li class="card" data-tags="['Example Tag', 'Test']">
<h3>Card Title</h3>
<p>Description</p>
<ul class="tags">
<li>Example Tag</li>
<li>Test</li>
</ul>
</li>
<li class="card" data-tags="['Test']">
<h3>Card Title</h3>
<p>Description</p>
<ul class="tags">
<li>Test</li>
</ul>
</li>
<li class="card" data-tags="['Example Tag', 'Test']">
<h3>Card Title</h3>
<p>Description</p>
<ul class="tags">
<li>Example Tag</li>
<li>Test</li>
</ul>
</li>
<li class="card" data-tags="['Example Tag']">
<h3>Card Title</h3>
<p>Description</p>
<ul class="tags">
<li>Example Tag</li>
</ul>
</li>
</ul>
</section>
// Function to sort a list by tag
function sortList() {
// Get all sections with filterable lists
let sections = document.querySelectorAll(".list-section");
// Set up logic for each section
sections.forEach(section => {
// Get list of all list items
let items = section.querySelectorAll(".item-list > li");
// Get the filter select input and add listener for the change event
let select = section.querySelector("select");
select.addEventListener("change", sort);
// Actually sorting the cards
function sort() {
// Look at each item in the array
items.forEach(element => {
// Remove the "hidden" attribute if the item has the tag selected or if the selection is "All"
// Otherwise, add the hidden attribute to the element
if (element.dataset.tags.includes(select.value) | select.value == "All") {
element.removeAttribute("hidden");
} else { element.setAttribute("hidden", true); }
});
};
// perform the sort funtion on initialization to cover edge cases, such as the user refreshing the page
sort();
});
}
// Initialize the list sorting function. This should be called on every page where a filterable list is available.
sortList();
@MattMcAdams
Copy link
Author

I need to close some chrome tabs and don't have time to digest this info right now, so here's some accessibility notes:

I think it would also be useful to test this page using VoiceOver just to see how it will actually be read / navigated by disabled users:

  • Test keyboard navigation
  • Test with voiceover

https://webaim.org/articles/voiceover/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment