skip to content

In the BEM CSS naming methodology, what do "block", "element" and "modifier" mean, and how does each one appear in a class name?

level: juniorimportance: must knowfreq 72%

answer

  1. component, part, variant
  2. the name carries the scope
  3. double underscore joins block to part
  4. double hyphen marks the variant
  5. modifier rides beside the base class

basics

~10 s

BEM names classes after a block (a standalone component, .card), its elements (parts that exist only inside it, .card__title), and modifiers (variant flags, .card--featured). Two underscores mark an element, two hyphens mark a modifier.

solid answer

~40 s

BEM stands for Block, Element, Modifier, and it encodes a component's scope directly in the class name because CSS itself has no scoping. A **block** is a standalone, meaningful piece of UI named for what it is, not how it looks: `.card`, `.site-search`. An **element** is a part that has no meaning outside its block, written `block__element` with two underscores: `.card__title`. A **modifier** is a flag that changes a block's or element's appearance or state, written with two hyphens: `.card--featured`, `.card__title--truncated`; it is added *alongside* the base class, never instead of it. Every rule is then a single class selector, so specificity is flat and source order decides conflicts. The element part stays flat no matter how deep the markup nests — `.card__title` even if the heading sits three `div`s down.

code

css · 5 lines
css
.card { display: grid; gap: 0.5rem; }
.card__title { font-size: 1.25rem; }
.card__meta { color: #666; }
.card--featured { outline: 2px solid #b30; }
.card__title--truncated { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

go deeper

for a junior

Be able to spell the three parts confidently — block, block__element, block--modifier — and say why the prefix exists at all: CSS has one global namespace, so the name carries the scope.

for a middle

Explain the mechanics: element names are flat regardless of markup depth, every rule is a single class so specificity stays equal, and a modifier holds only the delta from the base rule.

for a senior

Show judgment about where the boundaries fall — when a part earns promotion to its own block, why components must not own their outer geometry, and how mixes keep them context-free.

for a principal

Own the enforcement question: a convention nothing checks decays, so be ready to discuss linting the class pattern, keeping one spelling across teams, and what the convention costs in rename churn.

## Why a naming convention exists at all CSS has exactly one global namespace. A selector written anywhere matches anywhere in the document, so two engineers who both write `.title` in two different stylesheets silently fight over the same elements. BEM — Block, Element, Modifier, originally from Yandex — answers that by putting the scope into the name itself: the class *is* the namespace. The whole methodology is a grammar for class names plus one structural rule (one class per rule). ## Block A block is a standalone, meaningful chunk of interface that would still make sense if you moved it somewhere else on the page: `.card`, `.menu`, `.site-search`, `.pagination`. Two naming disciplines matter here. First, name it for **what it is**, never for how it looks or where it sits — `.card`, not `.blue-box` and not `.sidebar-thing`, because the colour will change and the sidebar will move. Second, a block should not set its own external geometry (outer `margin`, `position`, a `width` that only fits one slot), because that hard-codes one context into a component meant to be reusable. ## Element An element is a part of a block that has no standalone meaning — a card's title, a menu's item, a form's submit row. It is written with the block name, two underscores, then the element name: ```css .card { } .card__media { } .card__title { } ``` Two things surprise newcomers. The element name is **flat**: it names ownership, not DOM depth, so a heading nested three levels inside the card is still `.card__title`, not a path through its ancestors. And the class is used as a **single class selector** — you write `.card__title { }`, not `.card .card__title { }`; the prefix has already done the scoping work that a descendant selector would otherwise do. ## Modifier A modifier is a flag that changes appearance, state or behaviour of the block or element it hangs off: `.card--featured`, `.button--ghost`, `.card__title--truncated`. It is applied as an extra class next to the base one: ```html <article class="card card--featured"> <h2 class="card__title">Release notes</h2> </article> ``` The modifier rule carries only the *difference* from the base, which is why both classes must be present. ## The two spellings The original Yandex syntax marks modifiers with a single underscore and optionally a value: `block__elem_mod_val`. The variant most teams use today — popularised by the getbem.com write-up — is the "two dashes" style: `block__elem--mod`. Both are legitimate BEM; what is not legitimate is mixing them in one codebase, because the delimiters are the only thing telling a reader which part of the name is which. ## What the grammar actually buys - **Readability from the markup alone.** Seeing `class="card__footer"` in a template tells you which stylesheet component owns it, without grepping. - **Flat specificity by construction.** Every selector is one class, so they all weigh the same and conflicts resolve by source order rather than by who nested deeper. - **Safe deletion.** Removing a component means removing one name prefix; nothing else in the sheet claims those names. - **Visible misuse.** A `card__title` appearing outside a `card` is an obvious defect to a reviewer, which a generic `.title` never would be. ## Mixes: putting a block inside another block Because blocks must not own their outer positioning, BEM uses a **mix** — two entities on one DOM node: ```html <ul class="feed"> <li class="feed__item"> <article class="card">…</article> </li> </ul> ``` or, collapsing the node, `<article class="card feed__item">`. The `card` class supplies the component; the `feed__item` class supplies the parent's layout slot. The card stays context-free and reusable. ## The mistakes reviewers look for Chaining element names (`card__body__title`); naming blocks after appearance; applying a modifier without its base class; and re-introducing descendant selectors such as `.card .card__title`, which throws away the flat specificity the naming already guaranteed.

  • How do you decide whether something is an element of a block or a block in its own right?
    Ask whether it means anything outside its parent. A card's footer is meaningless alone, so it is `card__footer`. An avatar, a button or a badge is reusable elsewhere, so it is its own block — and where it sits inside a card, you mix the two classes on one node (`class="avatar card__avatar"`) so the card owns the placement and the avatar owns itself.
  • Is the two-dashes syntax the only correct BEM?
    No. The original Yandex convention marks modifiers with a single underscore and supports key/value modifiers, as in `menu__item_state_active`. The two-dashes form `menu__item--active` is a later, more widely adopted variant. Either is valid BEM; mixing both in one codebase is not, because the delimiters are the only signal of which part of the name is which.
  • Why does BEM insist a block should not set its own margin or position?
    Because those properties describe a relationship to a surrounding context, not the component. Baking them in means the block only fits one place. BEM pushes outer geometry onto the parent's element class — the mix pattern — so the same block drops into a sidebar, a grid cell or a modal without overrides.

Think of it as a filesystem path flattened into one word: the block is the folder, the element is the file inside it, and the modifier is a flag you pass alongside it rather than a different file.

saying these in an interview costs you the question

  • Says the element class only works nested under the block selector
  • Names blocks by appearance, like .blue-box or .left-column
  • Applies a modifier class alone, without the base class
  • Chains element names to mirror how deep the markup nests
  • Treats block, element and modifier delimiters as interchangeable

context