oxc-project/oxc · warning · OxcDiagnostic
Prefer `classList.toggle()` over `classList.add()` and `clas
Error message
Prefer `classList.toggle()` over `classList.add()` and `classList.remove()`
What it means
Lint diagnostic from oxlint's `unicorn/prefer-classlist-toggle` rule. The conditional pattern `el.classList.contains(x) ? el.classList.remove(x) : el.classList.add(x)` (or the `if/else` equivalent) is exactly what `classList.toggle(x)` does in one call — including the optional `force` second argument for explicit on/off. The rule flags that conditional and offers a fixer (guarded by `is_same_expression` so both branches really target the same element/class).
Source
Thrown at crates/oxc_linter/src/rules/unicorn/prefer_classlist_toggle.rs:18
use oxc_ast::{
AstKind,
ast::{CallExpression, ChainElement, Expression, IfStatement, MemberExpression, Statement},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use crate::{
AstNode,
context::LintContext,
fixer::{RuleFix, RuleFixer},
rule::Rule,
utils::is_same_expression,
};
fn prefer_classlist_toggle_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(
"Prefer `classList.toggle()` over `classList.add()` and `classList.remove()`",
)
.with_help("Use `classList.toggle()` instead")
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct PreferClasslistToggle;
declare_oxc_lint!(
/// ### What it does
///
/// Prefers the use of `element.classList.toggle(className, condition)` over
/// conditional add/remove patterns.
///
/// ### Why is this bad?
///
/// The `toggle()` method is more concise and expressive than using conditionalView on GitHub (pinned to e1e7af627c)
Solutions
- Replace the conditional with `el.classList.toggle('on')`, or `el.classList.toggle('on', force)` when you need explicit direction.
- Run `oxlint --fix`; the rule uses `is_same_expression` so only identical receivers/classes are rewritten — still glance at the diff.
- Keep the conditional and suppress inline (`// oxlint-disable-next-line unicorn/prefer-classlist-toggle`) if the branches differ (logging, counters).
- Disable the rule if the codebase standard uses explicit add/remove for clarity.
Example fix
// before
active ? btn.classList.add('on') : btn.classList.remove('on');
// after
btn.classList.toggle('on'); // or btn.classList.toggle('on', active) Defensive patterns
Strategy: validation
Validate before calling
// oxlint --fix --filter unicorn/prefer-classlist-toggle src/ // CI gate: oxlint --deny-warnings src/
Prevention
- Use `classList.toggle(name)` for flip logic and `classList.toggle(name, force)` for explicit state.
- Before suppressing, verify the two branches really do differ (extra side effects, different classes) — usually they don't.
When it happens
Trigger: `if (active) btn.classList.add('on'); else btn.classList.remove('on');`, ternary versions, and `toggle`-equivalent contains/add/remove chains on the same receiver expression. Detected during oxlint runs when the rule can match add/remove branches with identical target and class name.
Common situations: Theme switchers, selection state, hamburger buttons — anywhere UI state toggles a class. Very frequent in hand-written vanilla JS. When adopting oxlint's unicorn rules it appears in dozens of places at once. Careful with dynamic class names in branches (`add('a')` vs `remove('b')`) — those will not match, and false suppressions around similar code hide real bugs.
Related errors
- Don't use a zero fraction in the number.
- Don't use a dangling dot in the number.
- Unexpected number literal prefix in uppercase.
- Unexpected exponential notation in uppercase.
- Unexpected hexadecimal digits in lowercase.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/ba78ec911ab16312.
Report an issue: GitHub.