Naming, BEM & Design Tokens

Build scalable CSS architecture using the BEM naming convention and centralized Design Tokens.

CSS5 min readConcept 42 of 43

Bringing order to chaos

In a small project, naming a class .title works fine. In a massive application, .title will eventually clash with another developer's .title, causing unpredictable visual bugs.

BEM (Block, Element, Modifier) is a strict naming methodology that solves this. A **Block** is a standalone component (e.g., .card). An **Element** is a piece of that block (e.g., .card__image). A **Modifier** is a variation (e.g., .card--featured).

Design Tokens are the second half of the equation. Instead of hardcoding #3b82f6 everywhere, you store it in a CSS variable: --color-primary: #3b82f6;. These variables act as your single source of truth.

Scalability and theming

BEM guarantees that your CSS selectors will never clash. Because every element is prefixed with its block name, .card__title will never accidentally style .modal__title.

Furthermore, BEM keeps specificity extremely low. Almost every selector is a single class deep, which makes overriding styles predictable and easy.

When combined with Design Tokens, you achieve total control over your app's visual language. If marketing decides the primary brand color needs to be slightly darker, you change one --color-primary token, and every component updates instantly.

Implementing the architecture

First, define your tokens at the root: :root { --spacing-md: 16px; --color-brand: #ff0044; }.

Then, build your components using BEM and consume the tokens: .btn { padding: var(--spacing-md); background: var(--color-brand); }.

If you need a variation, use a modifier class: .btn--ghost { background: transparent; border: 1px solid var(--color-brand); }.

Try it

Adjust the global Design Tokens below. Notice how changing a single variable instantly flows through the BEM components.

Centralized Design System

/* 1. Global Design Tokens */
:root {
--color-brand:
;
--radius-base:
;
}
/* 2. BEM Components */
/* Block */
.card {
border-radius: var(--radius-base);
border-top: 4px solid var(--color-brand);
}
/* Element */
.card__title {
color: var(--color-brand);
}
/* Modifier */
.btn--outline {
border-radius: var(--radius-base);
color: var(--color-brand);
border: 2px solid var(--color-brand);
}
.card

Design Tokens.card__title

One variable change flows through the entire system instantly.

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1In the BEM class name `.nav-menu__item--active`, what does `item` represent?
  2. 2Why does BEM encourage using single classes (e.g. `.card__title`) instead of nested selectors (e.g. `.card .title`)?
  3. 3What is the primary benefit of using Design Tokens (CSS Variables) instead of hardcoded values?

Remember this

  • BEM (Block, Element, Modifier) prevents naming collisions and keeps specificity low.
  • Blocks are components (.btn), Elements are pieces (.btn__icon), Modifiers are variants (.btn--large).
  • Design Tokens (CSS Variables) act as the central nervous system for your app's visual design.
  • Updating a token at the :root instantly flows through the entire component tree.

Done with this concept?

Mark it complete to track your progress. No login needed.