How to Use classList.toggle for Toggleable UI Components: 5 Patterns from the dom-projects Repository
classList.toggle is a native DOM API method that adds a CSS class to an element when absent and removes it when present, returning a boolean indicating whether the class was added.
The jisan-mia/dom-projects repository demonstrates practical implementations of interactive UI components using vanilla JavaScript. Throughout this collection, classList.toggle serves as the primary state management mechanism for everything from search field reveals to todo completion markers, eliminating the need for separate boolean flags in your application logic.
Understanding the classList.toggle API
Element.classList.toggle() accepts a string argument representing the class name to toggle. When invoked, the method checks the element's current class list: if the specified class is absent, the browser adds it and returns true; if present, the browser removes it and returns false.
This declarative approach eliminates manual conditional logic. Instead of writing if/else blocks to check element.classList.contains('active') before adding or removing, a single call handles both operations atomically.
Implementation Patterns from dom-projects
Toggle Visibility for Search Components
In projects/search-field-reveal/script.js (lines 5-8), the repository implements a search field that expands when clicking a magnifying glass button. The pattern attaches a click listener to the button and toggles the active class on the container element.
const searchContainer = document.querySelector('.search');
const searchBtn = document.querySelector('.search-btn');
searchBtn.addEventListener('click', () => {
searchContainer.classList.toggle('active');
});
The CSS defines .search.active to show the input field, while the default state hides it. This approach stores the visibility state directly in the DOM rather than in a JavaScript variable.
Mark Items as Completed in Todo Lists
The projects/Todo-List-application/script.js file (lines 31-34) demonstrates toggling completion states. When a user clicks a checkbox, the application toggles the completed class on the parent list item element.
list.addEventListener('change', e => {
if (!e.target.matches('[data-list-item-checkbox]')) return;
const item = e.target.closest('.list-item');
item.classList.toggle('completed');
});
Accompanying CSS applies text-decoration: line-through and reduced opacity to .completed elements, providing immediate visual feedback without re-rendering the entire list.
Manage Exclusive Active States
For filter buttons in projects/advanced-todo/script.js (lines 90-100), the repository shows how to handle mutually exclusive selections. While classList.toggle works for binary states, exclusive groups require clearing the previous selection before activating the new one.
let previousFilterElm = null;
filterSection.addEventListener('click', e => {
if (!e.target.matches('button')) return;
// Clear stale active state
if (previousFilterElm) {
previousFilterElm.classList.remove('active-filter');
}
// Activate new selection
e.target.classList.add('active-filter');
previousFilterElm = e.target;
});
This pattern uses classList.remove for the previous element and classList.add for the new one, rather than toggle, to ensure only one button remains active at a time.
Coordinate Binary Mode Selections
In projects/scientific-calculator/js/script.js (lines 371-376), the calculator switches between radians and degrees using coordinated toggles. Two buttons share the same active-angle class, but only one should display it at a time.
radBtn.addEventListener('click', () => {
radBtn.classList.toggle('active-angle');
degBtn.classList.toggle('active-angle');
});
degBtn.addEventListener('click', () => {
degBtn.classList.toggle('active-angle');
radBtn.classList.toggle('active-angle');
});
Each click handler toggles both buttons simultaneously, transferring the active state from one to the other without explicit conditional checks.
Control Accordion Expansion
The morse code translator in projects/morse-translator/script.js (lines 262-266) implements collapsible FAQ sections. Clicking an accordion header toggles the is-open class, which CSS uses to show or hide the associated content panel.
accordionHeader.addEventListener('click', function() {
this.classList.toggle('is-open');
});
Critical Implementation Details
When implementing toggleable components, several edge cases require attention:
-
Prevent Default Form Submissions: In
projects/advanced-todo/script.js(line 27), form submission handlers calle.preventDefault()before toggling classes. Without this, page reloads reset the DOM state and destroy any toggled classes. -
Target the Correct Element: The repository consistently uses
Element.closest()to ensure classes toggle on the intended container rather than an inner element. For example, in todo applications, clicking a checkbox toggles the parent<li>, not the input itself. -
Initialize State from Storage: Applications like the advanced todo read from
localStorageduring initialization and render items with the correct initial classes. This prevents a mismatch between persisted data and UI state after page reload. -
Handle Multiple Visual States: In
projects/js-todo/script.js(lines 118-124), the code toggles multiple classes simultaneously—check,uncheck, andlineThrough—to coordinate checkbox appearance with text styling.
Summary
- classList.toggle atomically adds or removes a single class based on current presence, returning a boolean indicating the new state.
- The jisan-mia/dom-projects repository uses this API across six distinct implementations including search reveals, todo completions, and accordion panels.
- For mutually exclusive states, manually clear the previous selection with
classList.removebefore adding to the new element. - Always call
preventDefault()on form submissions that trigger toggles to avoid state loss from page reloads. - Use
Element.closest()to ensure event handlers target container elements rather than child triggers.
Frequently Asked Questions
Does classList.toggle work with multiple classes at once?
No, classList.toggle() accepts only one class name per invocation. To toggle multiple classes simultaneously, chain multiple calls: element.classList.toggle('class1'); element.classList.toggle('class2');. In projects/js-todo/script.js, the repository handles multiple visual states by toggling several related classes in sequence within the same event handler.
Can I use classList.toggle with CSS transitions?
Yes, classList.toggle pairs naturally with CSS transitions. When you toggle a class that changes properties with transition defined in CSS, the browser animates the change automatically. The dom-projects repository relies on this behavior for smooth search field reveals and accordion expansions, defining transition properties in CSS while JavaScript only manages the class state.
How do I know if classList.toggle added or removed the class?
The method returns true if the class was added and false if it was removed. You can capture this boolean to branch logic: const wasAdded = element.classList.toggle('active'); if (wasAdded) { console.log('Activated'); } else { console.log('Deactivated'); }. This pattern appears in the scientific calculator implementation to synchronize binary button states.
Is classList.toggle better than manually checking classList.contains?
For simple binary states, classList.toggle produces cleaner, more maintainable code than explicit if/else blocks using classList.contains(). However, for exclusive groups where only one item should be active, the repository shows that manually calling classList.remove on the previous element and classList.add on the new one provides clearer intent and prevents race conditions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →