How Does BEM Structure CSS Class Names?
The Block Element Modifier (BEM) methodology is a front-end naming
convention developed to make CSS scalable, modular, and maintainable
across complex web applications. By establishing a clear relationship
between components, their internal parts, and their visual variations,
BEM eliminates naming conflicts and reduces CSS specificity wars. The
structure relies on breaking UI patterns into three clear layers—Blocks,
Elements, and Modifiers—connected by standardized delimiters
(__ and --) that make class names instantly
readable and self-documenting.
The Core Components of BEM
BEM divides every interface component into three distinct conceptual layers:
- Block: A standalone, independent component that
retains its meaning and functionality anywhere on a page. Examples
include
.card,.btn,.header,.menu, or.form. - Element: A tied-in sub-part of a block that has no
standalone meaning outside of its parent block context. Elements are
declared using the block name followed by a double underscore
(
__). Examples include.card__title,.card__image,.menu__item, or.form__input. - Modifier: A flag or variation that alters the
appearance, behavior, or state of a block or element. Modifiers are
declared using the target name followed by a double hyphen
(
--). Examples include.btn--primary,.card--featured,.menu__item--active, or.form__input--disabled.
Delimiter Syntax and Naming Rules
BEM relies on specific formatting rules to differentiate multi-word names from component hierarchies:
- Hyphens (
-) for Multi-Word Names: If a block, element, or modifier name consists of multiple words, it is written in standard kebab-case (e.g.,.main-navigation,.search-form__submit-button). - Double Underscores (
__) for Elements: The double underscore visually separates the parent block from its internal child element (e.g.,.accordion__panel). - Double Hyphens (
--) for Modifiers: The double hyphen designates an explicit state or theme modification (e.g.,.accordion__panel--collapsed).
The complete pattern resolves to
block-name__element-name--modifier-name.
Practical Implementation in HTML and CSS
Consider a standard user profile card. Rather than nesting tag selectors or generic classes, BEM establishes explicit classes for every visual node.
<article class="profile-card profile-card--featured">
<img class="profile-card__avatar" src="avatar.jpg" alt="User avatar">
<h2 class="profile-card__name">Jane Doe</h2>
<p class="profile-card__bio">Full-stack software engineer.</p>
<button class="profile-card__button profile-card__button--primary">Follow</button>
</article>In the stylesheet, all classes remain at a single level of specificity (0-1-0), avoiding deeply nested CSS selectors:
/* Block */
.profile-card {
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 16px;
}
/* Block Modifier */
.profile-card--featured {
border-color: #3b82f6;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
/* Elements */
.profile-card__avatar {
border-radius: 50%;
width: 64px;
height: 64px;
}
.profile-card__name {
font-size: 1.25rem;
font-weight: 700;
margin-top: 8px;
}
.profile-card__bio {
color: #64748b;
font-size: 0.875rem;
}
.profile-card__button {
padding: 8px 16px;
border-radius: 4px;
}
/* Element Modifier */
.profile-card__button--primary {
background-color: #3b82f6;
color: #ffffff;
}Key Advantages of the BEM Architecture
Adopting BEM provides substantial architectural benefits for individual developers and large teams alike:
- Low and Predictable Specificity: Because every
styled node has its own distinct class, selectors do not need to be
chained (e.g.,
.profile-card .profile-card__name). This eliminates specificity wars and removes the need for!important. - Self-Documenting Code: Developers can look at a single class in HTML and immediately deduce which block it belongs to, whether it is a child element, and whether a modifier is being applied.
- Component Encapsulation: Styles defined for one block cannot accidentally leak into or overwrite styles in another block, even if elements share similar generic roles like titles or buttons.
- Reusability: Clean separation of modifiers allows developers to build flexible design systems where core block properties remain decoupled from theme-specific visual overrides.