In this post, we’ll explore how to toggle CSS classes on HTML elements using JavaScript and data attributes. This approach keeps your JavaScript generic and reusable – instead of writing a separate click handler for every toggle, you define the target and class name directly in the HTML.
Using data attributes as JavaScript hooks is a best practice for separation of concerns. CSS classes stay for styling, and
data-*attributes drive behavior. This means you can restyle elements without breaking functionality, and vice versa.
Basic HTML Setup
First, let’s look at the basic HTML structure. We’ll use a button to toggle a class on a target element. The JavaScript uses querySelectorAll to find all toggle triggers.
<button data-toggle-target="#content" data-toggle-class="highlight">Toggle Highlight</button>
<div id="content">This is the content to be toggled.</div>
JavaScript to Toggle Classes
Next, we’ll add JavaScript to handle the click event on the button and toggle the specified class on the target element.
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('[data-toggle-target]').forEach(button => {
button.addEventListener('click', () => {
const targetSelector = button.getAttribute('data-toggle-target');
const className = button.getAttribute('data-toggle-class');
document.querySelectorAll(targetSelector).forEach(target => {
target.classList.toggle(className);
});
});
});
});
The force Parameter
The classList.toggle() method accepts an optional second parameter called force. When force is true, the class is only added (never removed). When false, it is only removed (never added). This is useful for conditionally setting state:
// Only add the class when a condition is true
element.classList.toggle('active', isExpanded);
// Equivalent to:
if (isExpanded) {
element.classList.add('active');
} else {
element.classList.remove('active');
}
Using the dataset Property
The code above uses getAttribute() to read data attributes. An alternative is the dataset property, which converts data-* attribute names to camelCase:
const targetSelector = button.dataset.toggleTarget; // reads data-toggle-target
const className = button.dataset.toggleClass; // reads data-toggle-class
Both approaches work identically. dataset is slightly more concise, while getAttribute() is more explicit and works with attribute names that don’t follow the data- convention.
Styling with CSS
For this example, let’s add some CSS to see the effect of toggling the class.
.highlight {
background-color: darkolivegreen;
}
Here’s a live example:
Multiple Targets
You can also toggle classes on multiple target elements. Update the HTML to target multiple elements and see the changes.
<button data-toggle-target=".content" data-toggle-class="highlight">Toggle Highlight on All</button>
<div class="content">Content 1</div>
<div class="content">Content 2</div>
The HTML includes buttons with data-toggle-target and data-toggle-class attributes. The same JavaScript selects all elements with data-toggle-target and adds a click event listener. When a button is clicked, it toggles the specified class on the target element(s).
For toggle buttons that show/hide content, add aria-expanded="false" to the button and update it with JavaScript when toggled. This helps screen readers announce the current state to users.
Here’s a live example:
FAQs
Common questions about toggling classes with JavaScript and data attributes:
classList.toggle() adds the class if it is absent and removes it if it is present - a single method that handles both directions. classList.add() and classList.remove() only go one way. Use toggle() when you want a switch effect, and add()/remove() when you need explicit control over the final state..js-toggle as a JavaScript hook, renaming or removing it during a CSS refactor can break your scripts. Data attributes like data-toggle-target are clearly meant for JavaScript, so designers and developers can work independently without conflicts.classList.toggle(className, force) controls the direction. When force is true, the class is only added. When false, the class is only removed. This is useful for syncing the class with a boolean condition, like element.classList.toggle('open', isMenuOpen).classList.toggle() accepts only one class at a time. To toggle multiple classes, call it once for each: element.classList.toggle('a'); element.classList.toggle('b');. Alternatively, you can extend the data attribute approach to accept a space-separated list of classes and split them in JavaScript.getAttribute('data-toggle-target') uses the full attribute name and is more explicit. dataset.toggleTarget uses camelCase and is more concise. Performance is identical in modern browsers. Pick one style and stay consistent across your codebase.Summary
Data attributes provide a clean way to wire toggle behavior directly in HTML without writing per-element JavaScript. The same generic script handles any number of buttons, targets, and class names.
Use the force parameter of classList.toggle() when you need to sync a class with a boolean condition rather than flip it back and forth.
For accessibility, add aria-expanded to toggle buttons that show or hide content so screen readers can announce the current state.

