SMACSS categorizes every rule in a stylesheet into one of five buckets: Base, Layout, Module, State, and Theme. While its Module category overlaps heavily with BEM's Block, its State category fills a gap most other methodologies leave unaddressed.
1The Five Categories At A Glance
Base styles bare HTML elements with no class (body, a, h1). Layout divides the page into major regions, using IDs for unique regions or an l- prefixed class for reusable ones (.l-sidebar). Module covers reusable, self-contained components — SMACSS's equivalent of a BEM Block. State describes how a module currently looks due to interaction or JavaScript (.is-active). Theme optionally layers on visual reskinning (color schemes, branding) separate from structural module styles.
Most projects lean heavily on Module and State day-to-day, with Base and Layout established early and touched rarely afterward — a similar pattern to how ITCSS's foundational layers stabilize quickly while Components keeps growing.
2Why State Classes Are SMACSS's Best Idea
Most naming methodologies handle permanent visual variants well (BEM's Modifiers, for instance) but say little about *temporary, toggled* state driven by JavaScript — a menu that's open, a tab that's active, a form field that's invalid. SMACSS fills this gap directly with the is- (and sometimes has-) prefix: .is-open, .is-loading, .is-invalid.
The convention pays off in two ways. First, it's instantly greppable — searching a codebase for is- prefixed classes reliably finds every piece of dynamic, JS-toggled styling. Second, it separates *what a component structurally is* from *what state it's currently in*, letting .nav-item stay stable while .is-active gets added and removed freely by script.
3State Classes Combine Cleanly With BEM Or CUBE CSS
You don't need to adopt SMACSS wholesale to benefit from its State category. Many BEM codebases borrow the is- prefix directly for dynamic state, using BEM naming for structure and modifiers, and SMACSS-style state classes for anything JavaScript toggles — the two conventions don't conflict because they answer different questions.
This is a useful general lesson about CSS methodologies: they're not mutually exclusive religions. ITCSS answers 'where does this rule live', BEM answers 'what do I call this class', and SMACSS's State category answers 'how do I express that this is temporary'. Mature codebases frequently combine pieces of all three.
4Step-by-Step Breakdown
Five Categories For Every Rule. SMACSS (pronounced 'smacks') sorts every rule in your stylesheet into one of five categories: Base, Layout, Module, State, and Theme. Its standout contribution is the State category — a clean, dedicated vocabulary for styling things that change dynamically, like .is-active or .is-collapsed.
Base And Layout: The Foundation. Base rules are unqualified element defaults — body, a, h1 — the styling every instance of that tag gets with no class needed. Layout rules divide the page into major regions using either ID selectors (unique regions like #header) or a l- prefixed class for reusable layout patterns (.l-grid).
Base vs Layout. In SMACSS, which category do unqualified, tag-only rules like a { color: blue; } belong to?
- →Base
- →Layout
- →Module
Module: Reusable, Independent Components. Modules are SMACSS's equivalent of BEM's Block: reusable, self-contained UI pieces like .card or .nav. Sub-parts use a single-hyphen convention (.nav-item) rather than BEM's double underscore, but the underlying intent — component-scoped, self-contained styling — is identical.
Modules As Components. What is a SMACSS Module conceptually equivalent to in BEM terminology?
- →A Block
- →An Element
- →A Modifier
State: SMACSS's Standout Contribution. State classes describe how a module currently looks due to a JavaScript-driven or interaction-driven change: .is-active, .is-collapsed, .is-disabled. The is- prefix instantly signals 'this is temporary and toggled', separating dynamic state from a module's permanent structural or cosmetic classes.
State Classes. Why does SMACSS recommend a distinct is- prefix for state classes instead of just adding another modifier?
- →Purely to keep class names shorter
- →To clearly signal the class represents temporary, JS-toggled state rather than a permanent style variant
- →Because the browser treats is- prefixed classes specially
SMACSS Categories Mapped. You now know SMACSS's five categories and, most importantly, why its State category — the is- prefix convention — is worth adopting even inside a BEM or CUBE CSS codebase, since neither of those methodologies has as clean a built-in answer for dynamic, JavaScript-driven UI state.
Write A SMACSS State Rule. SMACSS state classes like is-active describe a temporary condition, layered on top of the base styles.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1State Classes Must Stay In Sync With Their ARIA Equivalents
A `.is-expanded` class toggled by JavaScript should always be paired with the corresponding `aria-expanded="true"` attribute update — the CSS class controls visual state, but assistive technology depends on the ARIA attribute, not the class name.
2Theme-Layer Overrides Must Be Re-Audited For Contrast
When a Theme layer reskins a module's colors, it can silently violate the contrast ratios the base Module was designed to satisfy — every theme variant needs its own accessibility contrast check, not just the default.
SEO Implications
- 1
Clear State/Structure Separation Simplifies CSS-in-Critical-Path Decisions
Because SMACSS state classes are additive and toggled at runtime, tooling can more easily identify that a module's base styles (not its state variants) are what's needed for initial critical-path CSS.
- 2
A Small, Stable Base Layer Benefits From Aggressive Caching
Base and Layout rules change rarely once established, making them good candidates for a separately cached bundle that avoids re-download on deploys that only touch Modules.
Best Practices
Never Use State Classes As The Sole Styling Hook For A Component's Core Appearance
State classes should only ever modify an existing module — a `.is-active` class with no corresponding base `.nav-item` class breaks the separation of concerns SMACSS is built around.
Keep The Theme Layer Optional And Additive
Not every project needs a Theme layer — only introduce it when you have genuine, swappable visual reskinning requirements (like light/dark mode or white-labeling), rather than by default.
Frequent Bugs
A JavaScript-toggled 'active' class doesn't match what screen reader users experience.
The `.is-active` class was updated without also updating `aria-expanded` or `aria-selected` — keep the two in sync on every toggle.
A dark-mode theme variant introduces text that fails contrast checks.
Audit contrast ratios per theme independently; a Theme layer overriding colors can break assumptions the base Module's contrast was designed around.
Real-World Examples
A Toggleable Accordion Using SMACSS State
An accordion component where JavaScript toggles both a SMACSS state class and its matching ARIA attribute together, keeping visual and assistive-technology state in sync.
el.classList.toggle('is-expanded');
el.setAttribute('aria-expanded', String(isExpanded));