ESC

Type to search the knowledge base.

BEM Naming Methodology

Block, Element, Modifier naming for CSS — how it limits specificity wars, what to name, and when utility or CSS modules beat strict BEM.

beginner3 min read
  • css
  • bem
  • architecture

BEM (Block Element Modifier) is a naming convention, not a runtime. It keeps class names predictable so you can reason about cascade without climbing specificity: blocks stand alone, elements belong to a block, modifiers flip state or variant.

Origin notes: getbem.com, still the clearest short reference. Pair with modern tooling (CSS modules, layers) rather than treating 2014 blog posts as law.

The three pieces

Piece Meaning Example
Block Standalone component .card, .search-form
Element Part of a block, no standalone meaning .card__title, .search-form__input
Modifier Flag for state/variant .card--featured, .card__title--muted
<article class="card card--featured">
  <h2 class="card__title">Billing</h2>
  <p class="card__body">Invoice history and payment methods.</p>
  <button type="button" class="card__action card__action--primary">Manage</button>
</article>
.card {
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  padding: 1rem;
}

.card--featured {
  border-color: var(--brand);
  box-shadow: 0 0 0 1px var(--brand);
}

.card__title {
  margin: 0 0 0.5rem;
  font-size: 1.125rem;
}

.card__action--primary {
  background: var(--brand);
  color: white;
}

Conventions vary (-- vs _ for modifiers). Pick one house style and stick to it. Double underscore __ for elements and double hyphen -- for modifiers is the common web default.

Rules that actually matter

  1. Elements don’t nest in the name — .card__header__title is a smell. Prefer .card__title or a new block .card-header if it grows complex.
  2. Elements depend on their block — don’t reuse .card__title under .modal without the block class context you designed for.
  3. Modifiers attach to what they change — .card--large or .card__title--large, not a vague .large on a random node.
  4. Avoid element-element selectors — .card .card__title is redundant if the class is already unique; prefer a single class for specificity sanity.
/* Prefer */
.card__title { font-weight: 600; }

/* Avoid specificity climb */
.card .card__header .card__title { font-weight: 600; }

Why teams adopt it

  • Searchability — grep card__ to find all parts.
  • Flat specificity — mostly single classes; overrides are intentional modifiers or utilities.
  • Parallel to components — maps cleanly to React/Vue component files.
  • Safe refactors — renaming a block is a find-replace of a prefix.

Where BEM fights you

Strict BEM gets noisy:

<button class="btn btn--primary btn--large btn--loading is-disabled">…</button>

Mitigations:

  • CSS modules / scoped CSS — local names; BEM-like structure inside the file still helps.
  • Utility classes for spacing/color one-offs (mt-4) instead of .card--mt-4.
  • State classes like .is-open as a documented exception (some teams use only BEM modifiers).
  • @layer so utilities win without !important wars.

BEM-ish without religion

/* Block */
.menu { }

/* Elements */
.menu__list { }
.menu__item { }
.menu__link { }

/* Modifiers */
.menu--vertical { }
.menu__link--active { }

For a tiny site with five classes, pure BEM is optional. For a multi-team design system with shared CSS, conventions beat clever nesting.

Interview out-loud

“BEM names components as blocks, parts as elements with __, and variants as modifiers with --. The goal is flat, readable class selectors and clear ownership. I avoid deep element chains in the name, keep modifiers explicit, and combine BEM with layers or modules so utilities and themes stay manageable. I’m fine mixing utilities for layout spacing rather than inventing a modifier per margin.”

Footguns

  1. Encoding every visual tweak as a modifier until class lists are unreadable.
  2. Nesting Sass as .card { &__title { .card & { … } } } until compiled selectors are unmaintainable.
  3. Sharing an element class across unrelated blocks.
  4. Using IDs or tag+class for “quick fixes” that defeat the specificity model.
  5. Treating BEM as a substitute for accessible markup — names don’t fix missing labels.

Further reading

Related guides