BEM is the most widely adopted CSS naming convention because it's mechanical rather than subjective — given any component, there's exactly one correct way to name its parts, removing the debate that unstructured naming invites.
1The Three Parts, Precisely Defined
A Block is an independent, reusable component: .card. An Element is a part of that block with no standalone meaning, joined with a double underscore: .card__title. A Modifier is a variant or state of a block or element, joined with a double hyphen: .card--featured or .card__title--large.
The formula is deliberately mechanical: given any piece of UI, you name the containing block, then its parts as elements, then any variants as modifiers. There's rarely ambiguity about what to call something, which is precisely BEM's core value proposition over ad-hoc naming.
2Elements Are Always Flat, Never Nested Twice
A common early mistake is mirroring deep DOM nesting in the class name — .card__header__title for a title nested inside a header nested inside a card. Strict BEM rejects this: an element attaches directly to its block, always, regardless of how deep it sits in the actual markup.
The reasoning is architectural, not stylistic: elements exist to describe a *relationship to the block*, not a *position in the DOM tree*. .card__title is understandable and stable even if you later move the title out of a .card__header wrapper — the DOM structure changed, but the component relationship (title belongs to card) didn't.
3When BEM's Verbosity Is Actually Worth It
BEM class names are long, and that's a deliberate trade-off, not an oversight. On a small project with one contributor, the verbosity may not pay for itself. On a large team where developers frequently touch components they didn't write, the payoff is substantial: .card__title--featured tells any reader its exact scope and relationship instantly, without opening the stylesheet.
The pattern also plays exceptionally well with component-based frameworks, since a BEM block maps naturally onto a single component file — the naming convention and the code organization reinforce each other rather than fighting.
4Step-by-Step Breakdown
Block__Element--Modifier. BEM (Block, Element, Modifier) turns component-based thinking into a strict, mechanical naming formula: every class name alone tells you exactly what it is and how it relates to everything around it, without needing to read any surrounding CSS or HTML nesting to understand it.
Block: The Standalone Component. A Block is a self-contained component that makes sense on its own: .card, .menu, .form. It never depends on being inside another block to be meaningful, and its name is a plain noun describing what it is, not where it lives.
Identifying Blocks. Which of these is correctly formatted as a BEM Block class name?
- →.card
- →.card__title
- →.card--large
Element: A Part That Only Makes Sense Inside Its Block. An Element is a piece of a block that has no independent meaning outside it, written as block__element. .card__title only makes sense as part of .card — it's never reused standalone, and critically, elements are never nested more than one level: there's no .card__title__text.
The Flat Element Rule. In strict BEM, why is .card__title__text considered incorrect?
- →It's simply too long a class name
- →BEM elements are always flat relative to their block — double-nesting elements isn't valid
- →It's actually correct BEM syntax
Modifier: A Variant Or State. A Modifier changes the appearance or state of a block or element, written as block--modifier or block__element--modifier. It's always applied alongside the base class, never alone — .card--featured still needs .card present on the same element.
Modifiers In Practice. In BEM, does .card--featured ever appear on an element without the .card class also present?
- →Yes, modifiers can fully replace the base class
- →No — modifiers are always applied together with their base block or element class
- →It depends on the specific project
BEM Fluency Achieved. You can now name any component using strict BEM syntax: a standalone Block, its flat Elements, and its Modifiers for variants and state. BEM's verbosity is the trade-off for its single biggest benefit — a class name alone tells you everything about a rule's scope and relationships, with zero ambiguity.
Target A BEM Element Class. BEM names an element's class as block__element — write a rule that targets it directly.
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)
1BEM Modifiers Should Reflect Visual State In Sync With ARIA State
When a `.button--disabled` modifier is applied, the corresponding `disabled` attribute or `aria-disabled` must be applied to the same element, since CSS classes alone communicate nothing to assistive technology.
2Predictable Naming Makes Accessibility Review Faster On Unfamiliar Components
A reviewer unfamiliar with a component can infer its structure purely from BEM class names, making it faster to spot missing focus states or ARIA attributes without first reverse-engineering the component's DOM.
SEO Implications
- 1
BEM's Flat Elements Keep Selectors Low-Specificity By Construction
Because BEM classes are always single-class selectors by convention, they avoid the deep descendant chains that increase style-matching cost during layout and paint on large pages.
- 2
Consistent Naming Improves Automated CSS Tooling Accuracy
Tools that detect unused CSS or generate documentation can parse BEM's mechanical Block__Element--Modifier structure far more reliably than free-form class names, indirectly supporting leaner shipped stylesheets.
Best Practices
Name The Block First, Then Derive Elements And Modifiers From It
Starting from the block keeps the naming grounded in the component's identity rather than accidentally mirroring DOM structure, which is the most common source of BEM naming mistakes.
Reserve BEM For Components, Not For Utility Classes
Utility classes like `.mt-4` intentionally break BEM's block-relationship model because they're meant to be atomic and reusable everywhere — mixing the two systems for the same class is a common source of confusion.
Frequent Bugs
An element class was renamed to match new DOM nesting, breaking every reference to it in JavaScript.
Elements should describe the block relationship, not DOM position — keep `.card__title` stable even if it moves to a different wrapper inside the card.
A modifier class is applied without its base block class, and none of the expected styles appear.
Modifiers only ever override specific properties; always apply the base block/element class alongside any modifier.
Real-World Examples
A Complete BEM Card Component
A pricing card component using the full Block, Element, Modifier structure for its featured-plan variant.
<div class="card card--featured">
<h3 class="card__title">Pro Plan</h3>
<button class="card__cta card__cta--primary">Subscribe</button>
</div>