# Add, remove, and toggle CSS classes with JavaScript

Use the `classList` API to add, remove, toggle, check, or replace CSS classes on
an element. Unlike string manipulation, it handles whitespace and duplicate
classes for you.

The element-selection methods used in these examples are covered in
[this DOM query guide](/getting-dom-elements-with-javascript).

## Add and remove classes

Select an element, then call `classList.add()` or `classList.remove()`:

```js
const element = document.querySelector('#foo')

if (element) {
  element.classList.add('active')
  element.classList.remove('hidden')
}
```

Class names do not include the dot used in CSS selectors. Pass `'active'`, not
`'.active'`.

Both methods accept multiple class names:

```js
element.classList.add('active', 'highlighted')
element.classList.remove('hidden', 'disabled')
```

If the classes are in an array, spread it into the method:

```js
const classes = ['active', 'highlighted']

element.classList.add(...classes)
```

Adding an existing class or removing a missing class has no effect.

## Toggle a class

`toggle()` adds a class when it is missing and removes it when it is present. It
returns `true` when the class is present after the call:

```js
const button = document.querySelector('#menu-button')
const menu = document.querySelector('#menu')

button?.addEventListener('click', () => {
  const isOpen = menu?.classList.toggle('open') ?? false

  button.setAttribute('aria-expanded', String(isOpen))
})
```

Pass a second boolean argument when the class should reflect a condition. This
is clearer than separate `add()` and `remove()` branches:

```js
element.classList.toggle('selected', isSelected)
```

When `isSelected` is `true`, the class is added. When it is `false`, the class
is removed.

## Check or replace a class

Use `contains()` to test for a class:

```js
if (element.classList.contains('active')) {
  console.log('The element is active')
}
```

Use `replace()` to swap one class for another:

```js
element.classList.replace('loading', 'loaded')
```

`replace()` returns `false` and makes no change if the old class is missing.

## Change classes on multiple elements

`querySelectorAll()` returns a `NodeList` with a `forEach()` method. You do not
need to convert it to an array:

```js
const accordionItems = document.querySelectorAll('.accordion-item')

accordionItems.forEach(item => {
  item.classList.remove('open')
})
```

## Using classList with TypeScript

DOM queries can return `null`, so check the result before using it. A generic
type argument is useful when you also need properties specific to an element:

```ts
const button = document.querySelector<HTMLButtonElement>('#submit-button')

if (!button) {
  throw new Error('Submit button not found')
}

button.addEventListener('click', () => {
  const isLoading = button.classList.toggle('loading')

  button.disabled = isLoading
})
```

Functions that only manipulate classes can accept the broader `Element` type:

```ts
function setSelected(element: Element, selected: boolean): void {
  element.classList.toggle('selected', selected)
}
```

## When to use className

The `className` property reads or replaces the entire class attribute:

```js
element.className = 'card featured'
```

This removes every existing class before setting the new value. Use it only when
replacing the complete class list is intentional. For individual classes, prefer
`classList` over string concatenation or regular expressions.

See the
[MDN classList reference](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList)
for the full API.
