You add a class in your HTML and the styling appears right away. The colors change, the layout shifts, and everything looks correct. Then you try to add or remove that same class with JavaScript using classList.toggle(), and nothing happens at all.
This is one of the most confusing problems for beginners because the CSS itself is clearly fine. The issue is almost never the style rule. It is usually the timing of your script, the element you selected, a small typo, or another rule that is quietly overruling the class you are trying to toggle.
Quick Answer
If a CSS class works in static HTML but a JavaScript toggle does nothing, check three things first: your script is running after the element exists, you selected the correct element, and the class name in JavaScript matches the CSS exactly with no dot in front of it. Also open DevTools and confirm the class actually appears on the element when your code runs. If the class appears but the style does not change, you have a CSS specificity or loading problem, not a JavaScript problem.
How Class Toggling Is Supposed to Work
When you write a class directly in HTML, the browser reads it while building the page. The matching CSS rule applies immediately. When you toggle a class with JavaScript, you are asking the browser to change that list of classes after the page has loaded.
The method element.classList.toggle('active') does two jobs. If the class is not present, it adds it. If the class is already present, it removes it. It also returns true when it added the class and false when it removed it, which is useful for debugging.
Notice there is no dot before the name. In CSS you write .active to target a class. In JavaScript you write only active. Adding the dot is a very common mistake that makes the toggle silently create a useless class name that no style rule will ever match.
Step-by-Step Checklist to Find the Problem
Step 1: Make Sure the Script Runs After the Element Exists
If your script tag sits in the head of the document without any waiting logic, it runs before the browser has built the elements below it. Your selection returns null, and the toggle never reaches a real element.
- Move your script tag to just before the closing body tag, or add the
deferattribute to an external script. - Or wrap your code in a listener such as
document.addEventListener('DOMContentLoaded', ...)so it waits for the HTML to be parsed. - Log the selected element with
console.log(element)and confirm you see the element, notnull.
Step 2: Check That You Selected the Right Element
Selectors are another frequent cause. document.querySelector('.menu') returns only the first match. If you have several similar elements, you may be toggling a hidden or unrelated one while looking at a different one on screen.
- Use
querySelectorAllwhen you need to toggle every matching item, then loop over the list. - Check for typos between the HTML class, the CSS selector, and the JavaScript selector.
- Confirm IDs and classes are not mixed up:
#is for IDs in selectors,.is for classes.
Our guide on how to select DOM elements correctly in JavaScript walks through the differences between these methods in more detail.
Step 3: Verify the Class Actually Changes in DevTools
- Right-click the element in the browser and choose Inspect.
- Trigger the action that should toggle the class, such as a button click.
- Watch the
classattribute in the Elements panel. Does it change? - If it changes, your JavaScript works and the problem is in CSS. If it does not change, your JavaScript is not running or is failing earlier.
Step 4: Look for Errors in the Console
A single error earlier in a script stops the rest of that script from running. Open the Console tab and reload the page. Messages such as Cannot read properties of null usually mean the element was not found. A message about a function not being defined means the click handler was never connected properly.
The documentation for the Element classList API on MDN Web Docs explains toggle, add, remove, and contains with clear examples you can compare against your own code.
Step 5: Rule Out CSS Specificity and Order
Sometimes the class is added correctly, but another rule wins. For example, a rule using an ID selector or a long selector chain can beat a single class rule. Inline styles set directly on the element can also beat a class.
- In DevTools, select the element and look at the Styles panel to see which rule is actually applied and which rules are crossed out.
- Check whether your stylesheet is loaded after any framework stylesheet that might override it.
- Avoid reaching for
!importantas a first fix. It hides the real problem and makes later styling harder. - Make sure the toggled class is defined in a stylesheet that is actually linked to the page, not in a file you forgot to include.
A Small Working Example to Compare Against
Sometimes the fastest test is a tiny isolated example. Create a button and a box, give the box a class in CSS that changes its background, and toggle that class on click. If the small example works, copy your real element into it step by step until it breaks. That breaking point tells you exactly where the fault lies.
Pay close attention to the event itself. If you attach the handler with addEventListener, make sure the button you click is the same button the listener is attached to. If you use an inline handler, make sure the function name matches exactly, including capital letters, because JavaScript is case sensitive.
Also consider forms. A button inside a form defaults to submit behavior in many cases, which reloads the page. The class may toggle for a split second and then disappear when the page reloads, making it look like nothing happened. Setting the button type to button or preventing the default action solves that confusing case.
Common Mistakes and Useful Tips
- Including the dot: Writing
toggle('.active')creates a wrong class name. Use only the name itself. - Script too early: Code in the head without
deferruns before elements exist. - Wrong element: Toggling the first match while looking at a second similar element.
- Hidden error above: An earlier error in the same file stops your toggle code from ever running.
- Framework re-rendering: In React, Vue, or similar tools, direct DOM changes can be overwritten when the component re-renders. Use the framework state instead.
- Tip: Log the result of toggle. If it returns
trueandfalsealternately, the logic works and you should focus entirely on CSS. - Tip: Use
classList.contains('active')in the console to check the current state at any moment.
Another helpful habit is to test the style by manually adding the class in DevTools. In the Elements panel you can add a class directly to the element. If the style appears when you add it by hand, your CSS is fine and the fault is in how or when JavaScript runs. If the style still does not appear, stop debugging JavaScript and fix the stylesheet first.
Conclusion
When a class works in HTML but a JavaScript toggle seems to do nothing, work through the problem in order: timing, selection, spelling, console errors, and then CSS specificity. In most cases the cause is simple, such as a script running too early, a dot in the class name, or a page reload from a form button. Checking in DevTools whether the class attribute actually changes splits the problem in half instantly. Once you know whether the fault is in JavaScript or CSS, the fix is usually only a line or two.
Frequently Asked Questions
Why does classList.toggle return true but the style does not change?
The class is being added, so JavaScript is working. The style is likely being beaten by a more specific rule, an inline style, or the class is defined in a stylesheet that is not loaded. Check the Styles panel in DevTools to see which rule wins.
Should I use a dot before the class name in toggle?
No. In CSS selectors you write a dot, but in classList methods you pass only the class name itself, such as 'active'. Adding a dot creates a different, unmatched class name.
Why does my toggle work once and then stop working?
This often happens when another piece of code re-renders or replaces the element, when the event listener is attached to an element that gets removed, or when a form submit reloads the page. Check the console and confirm the element still exists after the first interaction.
What is the difference between toggle, add, and remove?
add always adds the class, remove always removes it, and toggle switches between the two based on the current state. Toggle is best for menus, accordions, and other on-off patterns.
Can two classes with similar names cause this problem?
Yes. A small difference such as is-open in CSS and isOpen in JavaScript means the names never match. JavaScript and CSS class names are case sensitive in this context, so copy the exact name in all three places: HTML, CSS, and JavaScript.


Leave a Reply