search ]

Toggling Classes using JavaScript & Data Attributes

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:

This is the content to be toggled.

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:

Content 1
Content 2

FAQs

Common questions about toggling classes with JavaScript and data attributes:

What is the difference between classList.toggle() and classList.add()/remove()?
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.
Why use data attributes instead of classes as JavaScript hooks?
Data attributes separate styling from behavior. If you use a CSS class like .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.
What does the force parameter in classList.toggle() do?
The second parameter of 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).
Can I toggle multiple classes at once?
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.
Should I use getAttribute() or dataset to read data attributes?
Both work. 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.

Join the Discussion
0 Comments  ]

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!

Savvy WordPress Development official logo