---
name: bem-css-naming
source: https://app.decimal.ai/s/bem-css-naming@1/SKILL.md
source_sha256: 8c96c8881a26
---

# BEM CSS class naming

## Contract

Enforces the `block__element--modifier` class-naming grammar on every CSS class you name for a
UI component. Apply whenever the task is to name the classes for a component and its parts and
states; not to write the CSS declarations themselves and not to choose visual values.

## Rules

A component's class names are built from three kinds of name, joined by fixed delimiters:

1. **Block** — the standalone component, named on its own: `card`, `modal`, `nav`. Words within
   a single name are joined by a **single hyphen**: `site-header`, `product-card`.

2. **Element** — a part that belongs to a block, joined to the block name with a **double
   underscore** `__`: `card__title`, `modal__close`, `nav__item`. Never a single hyphen
   (`card-title`), never camelCase (`cardTitle`), never a descendant selector (`.card .title`).

3. **Modifier** — a variant or state flag on a block or element, joined with a **double hyphen**
   `--`: `card--featured`, `nav__item--active`, `button--disabled`.

4. **No element of an element.** Elements are always exactly one level under the block. A part
   nested visually inside another part is still `block__thing`, never `block__part__thing`:
   write `card__title`, not `card__header__title`.

5. **A modifier never stands alone.** It is applied *alongside* the base class, not instead of
   it: `class="button button--primary"`, never `class="button--primary"` by itself. The
   modifier only adjusts; the base carries the shared styles.

6. **Case + separators.** All name parts are lowercase. The three separators are distinct and
   fixed: single hyphen `-` inside a multi-word name, double underscore `__` before an element,
   double hyphen `--` before a modifier.

## Worked examples

The base's ad-hoc default is on the left; the conforming BEM names on the right.

A search form with a field, a submit control, and a disabled state:

```
BEFORE  .searchForm   .searchForm .input   .submitBtn   .disabled

AFTER   .search-form
        .search-form__field
        .search-form__submit
        .search-form--disabled
```

A media object (image beside body text) with a reversed variant:

```
BEFORE  .media   .media-img   .mediaBody   .media.reverse

AFTER   .media
        .media__image
        .media__body
        .media--reversed
```

An element that carries its own state — the modifier attaches to the element, used with it:

```
BEFORE  <li class="active">   /* bare state class */

AFTER   <li class="breadcrumb__crumb breadcrumb__crumb--current">
```

## Edge cases & exceptions

- **Deeply nested markup** → the class is still `block__element`. A label inside a field inside
  a form is `search-form__label`, not `search-form__field__label`. Flatten to one level.
- **A part that is really its own component** → promote it to a new block. A reusable button
  inside a card is `button` (its own block), not `card__button`, when it is used elsewhere too.
- **Multiple modifiers** → list each as its own class alongside the base:
  `class="button button--large button--primary"`.
- **Boolean state vs value** → a plain flag is `--active`/`--disabled`; a value uses a
  key-value form `--size-large` / `--theme-dark` (still the double-hyphen delimiter).

## Do / Don't

- Do join an element to its block with `__`. Don't use a single hyphen (`card-title`),
  camelCase (`cardTitle`), or a descendant selector.
- Do join a modifier with `--`. Don't use a single hyphen or a bare state class like `.active`.
- Do keep elements one level under the block. Don't chain `block__a__b`.
- Do apply a modifier alongside the base class. Don't replace the base with the modifier alone.
- Do lowercase every part. Don't PascalCase or camelCase block/element names.

## Common mistakes

- Ad-hoc names the base reaches for: `.cardTitle`, `.card-title`, `.card .title`, `.active`.
- Single underscore/hyphen where a double belongs (`card_title`, `card-title` for an element;
  `button-primary` for a modifier).
- Chaining elements: `menu__list__item` instead of `menu__item`.
- A lone modifier class in the markup with no base class.
- Mixing camelCase into a name part.

## Quick checklist

- Each part class is `block`, `block__element`, or `block[__element]--modifier`.
- Element delimiter is `__`; modifier delimiter is `--`; both are doubled.
- No element is chained under another element.
- Every modifier appears alongside its base class, never alone.
- All name parts are lowercase, words joined by single hyphens.
