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.
- 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
- Elements don’t nest in the name —
.card__header__titleis a smell. Prefer.card__titleor a new block.card-headerif it grows complex. - Elements depend on their block — don’t reuse
.card__titleunder.modalwithout the block class context you designed for. - Modifiers attach to what they change —
.card--largeor.card__title--large, not a vague.largeon a random node. - Avoid element-element selectors —
.card .card__titleis 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-openas a documented exception (some teams use only BEM modifiers). @layerso utilities win without!importantwars.
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
- Encoding every visual tweak as a modifier until class lists are unreadable.
- Nesting Sass as
.card { &__title { .card & { … } } }until compiled selectors are unmaintainable. - Sharing an element class across unrelated blocks.
- Using IDs or tag+class for “quick fixes” that defeat the specificity model.
- Treating BEM as a substitute for accessible markup — names don’t fix missing labels.
Related
- CSS architecture ITCSS overview
- Cascade layers @layer
- Utility-first CSS tradeoffs
- Cascade & specificity
Further reading
Related guides
- Cascade Layers @layerUse @layer to order reset, base, components, and utilities so specificity wars lose — layer priority, unlayered CSS, and !important.
- CSS Architecture ITCSS OverviewITCSS inverted triangle — settings through utilities — how layer order reduces specificity wars in large stylesheets.
- Utility-First CSS TradeoffsUtility-first (Tailwind-style) pros and cons — speed, consistency, HTML noise, design-token discipline, and when components still win.
- Accent Color and Form ControlsUse accent-color to theme native checkboxes, radios, ranges, and progress — what it paints, what it skips, and when to custom-style instead.
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.