BEM stands for Block, Element, Modifier. A block is a standalone component such as .card, an element is a part that only makes sense inside it, written .card__title with two underscores, and a modifier is a variation written .card--featured with two hyphens. Modifiers are added next to the base class, never instead of it.
| Part | Pattern | Example |
|---|---|---|
| Block | block | .search-form |
| Element | block__element | .search-form__input |
| Block modifier | block--modifier | .search-form--compact |
| Element modifier | block__element--modifier | .search-form__button--disabled |
| Key and value modifier | block--key-value | .search-form--theme-dark |
Updated
Naming is where CSS projects either stay tidy or slowly turn into a pile of overrides. This page explains the BEM rules from the official BEM site, checks your own class names as you type, and compares BEM with the other ways teams keep styles from colliding today.
Type a block, element and modifier to get class names, matching HTML and CSS, with warnings when a name breaks a rule.
| Approach | Example | Who keeps names unique | Best fit |
|---|---|---|---|
| BEM | .card__title--large | You, by convention | Plain CSS, Sass, CMS themes |
| Utility classes (Tailwind) | text-lg font-semibold | No component names needed | Apps built from components |
| CSS Modules | styles.cardTitle | The build tool rewrites names | React, Vue and similar with a bundler |
| @scope | @scope (.card) { h2 {} } | The browser limits the rules | Newer browsers, light markup |
Each selector is one class. The featured modifier changes the border and lets one element react through the block modifier.
<style>
.card { max-width: 280px; padding: 16px; border: 1px solid #e2e8f0; border-radius: 12px; margin-bottom: 10px }
.card--featured { border: 2px solid #2563eb }
.card__title { margin: 0 0 4px; font-size: 18px }
.card__price { margin: 0; font-weight: 700 }
.card--featured .card__price { color: #2563eb }
.card__tag { display: inline-block; font-size: 12px; padding: 2px 8px; border-radius: 99px; background: #f1f5f9 }
.card__tag--new { background: #dcfce7 }
</style>
<article class="card">
<h3 class="card__title">Starter</h3>
<p class="card__price">$9</p>
</article>
<article class="card card--featured">
<span class="card__tag card__tag--new">New</span>
<h3 class="card__title">Team</h3>
<p class="card__price">$29</p>
</article>| Wrong | Right | Why |
|---|---|---|
| .card__body__title | .card__title | Elements belong to the block, not to other elements |
| class="card--featured" | class="card card--featured" | A modifier needs its base class |
| .card .card__title | .card__title | Extra nesting adds specificity |
| div.card__title | .card__title | BEM selectors use class names only |
| .card--blue | .card--primary | Name the meaning, not the colour |
Every CSS class lives in one global namespace. Two developers writing .title in different files will eventually style each other's headings, and the usual fix, a longer selector, starts a specificity arms race.
A convention gives every class an owner. When .pricing-card__price misbehaves you know which component to open, and you can delete the component knowing its classes are not used elsewhere.
A block may sit inside another block. A button in a card stays .btn, and if the card needs to position it, the same element can carry both classes: class="btn card__action".
This mix keeps the button's own styles reusable while the card controls only layout, such as margin or alignment, through its element class.
@scope lets you limit rules to a subtree, for example everything inside .card but not inside a nested .card__media. It reached Baseline as newly available in 2026, so check your audience's browsers before relying on it alone.
Cascade layers solve a related problem: they let you rank whole groups of styles, so a reset or a third-party theme never outranks your components no matter how specific its selectors are.
Block, Element, Modifier. It is a naming method for CSS classes that keeps every selector to a single class, so specificity stays flat and you can tell from a class name which component it belongs to.
Single hyphens are already used inside names, as in search-form. Doubling the separators makes the boundary between block, element and modifier unambiguous, so .search-form__submit-button reads as one block and one element.
With utility classes you rarely write component class names, so BEM matters less. With CSS Modules the build tool scopes names for you, and short camelCase names are recommended. BEM is still a strong choice for plain CSS, Sass, WordPress themes and design systems shared across frameworks.
Attach it to the block, not to the parent element. A title inside a card body is .card__title, even when the HTML nests it inside .card__body. If the nested part is reusable on its own, make it a new block instead.
Related: CSS selectors cheat sheet, CSS specificity calculator, CSS frameworks compared, CSS variables, Modern CSS reset.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.