How to Fix "classList.filter is not a function" in JavaScript
If you've ever tried to filter class names on an HTML element using element.classList.filter(), you likely ran into a frustrating runtime error: TypeError: element.classList.filter is not a function.
In this guide, we'll break down why this error occurs, how to quickly fix it, and the best practices for reading dynamic data from HTML elements in modern JavaScript.
Why Does the Error Happen?
When you access an element's classList property, JavaScript returns a DOMTokenList object. While a DOMTokenList looks and behaves like an array in many ways (it has a .length property and zero-based indexing), it is not a true JavaScript Array.
Because it's not an Array instance, it does not inherit array prototype methods like .filter(), .map(), or .reduce(). Furthermore, class names inside classList do not contain leading dots (e.g., 'category-cards', not '.category-cards').
Solution 1: Convert classList to a Standard Array
The simplest fix is to convert the DOMTokenList into a native JavaScript Array using either Array.from() or the ES6 spread operator ([...]). Once converted, you can use .filter() freely.
// Get the closest parent container
const selectedCategoryDiv = selectedCategory.closest('.category-cards');
// Convert classList to an Array and filter
const category = [...selectedCategoryDiv.classList].filter(cls => cls !== 'category-cards');
console.log(category[0]); // Output: "nature", "triva", etc.Solution 2: Find the Specific Target Category
If you have a known set of allowed categories (e.g., nature, trivia, sports, food), a better approach is using Array.prototype.find() to get the exact category string rather than an array of remaining classes.
const targetCategories = ['nature', 'triva', 'sports', 'category-food'];
const selectedCategoryDiv = selectedCategory.closest('.category-cards');
// Find the first class that matches one of our target categories
const category = [...selectedCategoryDiv.classList].find(cls => targetCategories.includes(cls));
console.log(category); // Output: "nature"Solution 3: Best Practice - Use HTML Data Attributes
Relying on CSS class names for JavaScript logic can quickly become brittle. If someone renames or refactors a CSS class in the future, your script might break silently. The recommended modern practice is to use HTML data-* attributes to separate styling concerns from data logic.
Updated HTML:
<div class="category-cards" data-category="nature">
<h2 class="name-category">Nature</h2>
<p class="about-category">Test your wildlife knowledge.</p>
<button class="select-topic-category">Select Topic</button>
</div>Updated JavaScript:
const selectedCategoryDiv = selectedCategory.closest('.category-cards');
// Directly access the category via dataset
const category = selectedCategoryDiv.dataset.category;
console.log(category); // Output: "nature"Summary
element.classListis aDOMTokenList, not an Array.- To use
.filter(), convert it first using[...element.classList]orArray.from(element.classList). - Remember that class names in
classListdo not include leading dots. - For cleaner and more maintainable code, consider using
data-*attributes instead of parsing class strings.