How BEM works in CSS: block, element, modifier explained
Learn how BEM works in CSS with practical examples of blocks, elements, and modifiers. Understand the naming rules, common mistakes, and when to use BEM in large projects.
BEM (Block, Element, Modifier) is a CSS naming methodology created by Yandex in 2005. It divides CSS classes into three parts: a block describes a standalone component, an element describes a part of that block, and a modifier describes a variation in appearance or behavior. BEM makes class names self-documenting and prevents naming collisions in large stylesheets shared across multiple developers.
With the advancement of web applications, there is the requirement to build even more complex interfaces. These applications are likely to have several custom CSS classes. As a result, making the CSS class names readable and understandable becomes paramount. The BEM approach assists in this situation.
We'll examine the BEM methodology and how to use it to build large applications with custom CSS.
Prerequisite
A basic understanding of HTML and CSS is needed to follow this article.
The BEM methodology
Yandex, a Russian IT company, invented BEM in 2005. The main goal of BEM is to help maintain the structure, readability, and flexibility of CSS.
BEM stands for Block, Element, and Modifier. BEM divides CSS classes into independent modules, making collaboration with developers easier.
The community-standard BEM syntax uses a double underscore for elements and a double hyphen for modifiers:
.block {}
.block__element {}
.block--modifier {}
.block__element--modifier {}
BEM's original Yandex documentation uses a single underscore for modifiers (
.block__element_modifier). The community standard adopted by CSS-Tricks, getbem.com, and the majority of frontend teams uses a double hyphen (--) for modifiers. Single hyphens are already used in multi-word block names like.search-form, so the double hyphen makes the modifier boundary visually unambiguous. This guide uses the double-hyphen convention.
If we look at a random piece of source code online and see a class name like .btn__text--bold, that's BEM. The code .btn__text--bold is easy to understand even without prior knowledge of the codebase. That is the practical value of BEM.
BEM works only with CSS classes, not IDs or tag selectors. CSS classes enable reuse of the same name many times in a stylesheet.
What are the advantages of working with BEM?
There are several advantages to using BEM:
- Reusability: BEM's modular structure means fewer lines of code to maintain. Code written with BEM is flexible and manageable, which increases teamwork and productivity among developers.
- Fewer CSS conflicts: Because BEM class names are unique by construction (block name is always part of the element name), specificity battles and unintended overrides become rare.
- Structure: Code written with BEM is more organized, making it easier to read and onboard new developers onto a project.
- Predictability: When you see a class name, you immediately know which component it belongs to and what role it plays, without needing to hunt through the stylesheet.
BEM: the B represents a block
Blocks are significant elements that can stand on their own and can be reused in other parts of the CSS. Class attributes represent blocks in HTML. Block names are assigned to parent elements.
Some of the most common blocks found on websites are the header, content, sidebar, footer, and search component.
The block name answers the question "what is it for?" It is clear from the block name .btn that the developer is styling a button element.
.btn {
font-size: 2em;
color: red;
text-shadow: 1px 3px 1px black;
}
.input {
font-size: 2em;
color: red;
}
In the example above, the developer is styling the input element. The block name gives a clear picture of what the developer is doing.
The block name explains what the block does. It does not tell us what the block looks like.
Don't do this:
<!-- Wrong practice -->
<div class="green-content">
<h2>CSS Is Fun</h2>
</div>
.green-content describes appearance. It does not tell us the purpose of the block.
Do this instead:
<!-- Best practice -->
<div class="content">
<h2>CSS Is Fun</h2>
</div>
.content is meaningful. An external developer would understand the code without prior context.
Multi-word block names
The majority of block names consist of a single word: .input, .header, .btn, .content, .menu. For longer block names, divide each word with a single hyphen:
.btn-text.btn-color.menu-text
.btn-color {
font-size: 2em;
color: red;
text-shadow: 1px 3px 1px black;
}
Nesting block names
Blocks can be nested inside other blocks:
<header class="header">
<img src="#" alt="#">
<nav class="navbar">
<!-- Write your HTML elements -->
</nav>
</header>
The block .header contains another block .navbar nested inside it. Both are independent blocks in their own right.
BEM: the E represents an element
An element is always a part of a block. It cannot exist by itself and has no meaning unless placed alongside a block name. Element names are assigned to child elements.
The element name begins with a double underscore __.
.block-name__element-name {
/* write your CSS styles */
}
Like the block name, the element name answers the question "what is it for?" and gives a clear picture of the developer's intent.
Examples of element names:
.content__text.header__img.list__item
A practical example using .content as the block name:
<div class="content">
<h2 class="content__title">Always Code</h2>
<img class="content__img" src="#" alt="#">
<p class="content__description">Coding everyday yields results</p>
</div>
- Line 1: block
.contentassigned to the parentdiv - Lines 2, 3, 4: child elements with names
.content__title,.content__img,.content__description. The element names are self-explanatory.
Like the block name, the element name describes what the element does, not what it looks like.
Don't do this:
<!-- Wrong practice -->
<div class="content">
<h2 class="content__bold">CSS Is Fun</h2>
</div>
.content__bold describes appearance. It does not tell us the purpose.
Do this instead:
<!-- Best practice -->
<div class="content">
<h2 class="content__title">CSS Is Fun</h2>
</div>
.content__title is meaningful and descriptive.
Nesting element names
When nesting, always use the pattern .block-name__element-name, regardless of how deep the HTML nests.
Don't do this:
<main class="main-content">
<div class="main-content__wrapper">
<h2 class="main-content__wrapper__title">Coding is fun</h2>
<p class="main-content__wrapper__description">Remember to code today</p>
</div>
</main>
.main-content__wrapper__title creates three-level nesting in the class name. This breaks BEM convention and makes class names difficult to refactor.
Do this instead:
<main class="main-content">
<div class="main-content__wrapper">
<h2 class="main-content__title">Coding is fun</h2>
<p class="main-content__description">Remember to code today</p>
</div>
</main>
All elements reference the block directly in the class name, regardless of how deep they sit in the HTML tree. This keeps names flat and easy to read.
BEM: the M represents a modifier
Both the block and element names describe what a component is. Modifiers are different: they tell us what the block or element looks like, its size, or its state.
The modifier name uses a double hyphen --.
.block-name--modifier-name {
/* write your CSS styles */
}
Or for an element modifier:
.block-name__element-name--modifier-name {
/* write your CSS styles */
}
Modifiers cannot stand alone. They are always used alongside a block or element name. It is not compulsory to use modifiers, they are added only when a variation is needed.
disabled, active, large, and bold are examples of modifier names.
Modifiers are useful when we want to change the styles of elements that share the same block name:
<button class="btn-text">
Sign up
</button>
<button class="btn-text btn-text--red">
Sign up
</button>
<button class="btn-text btn-text--bold">
Sign up
</button>
In the above code:
- Three button elements share the same block name
.btn-text - Two buttons have modifier names
--redand--boldto distinguish their appearance from the default - The base class
.btn-textis always present, the modifier only adds or overrides styles on top of it
BEM vs other CSS methodologies
BEM is not the only CSS naming methodology. Two others commonly appear in comparisons.
OOCSS (Object-Oriented CSS) separates structure from skin. A structural class handles layout and positioning; a skin class handles colors and fonts. It promotes reuse but leaves naming conventions largely to the team, which can lead to inconsistency.
SMACSS (Scalable and Modular Architecture for CSS) organizes styles into five categories: base, layout, module, state, and theme. It is a strong file organization system but, like OOCSS, does not prescribe a naming convention.
BEM is the most explicit of the three. The class name itself carries the component relationship, so any developer reading the HTML knows exactly which styles apply and where. Many teams combine SMACSS file organization with BEM naming, a combination that gives both structure and readability.
Does BEM still make sense in 2026?
BEM was designed for global stylesheets shared across teams. In 2026, many projects use Tailwind CSS, React with CSS Modules, or CSS-in-JS. Where does BEM fit?
With Tailwind CSS: Tailwind replaces most of what BEM does by composing utility classes in HTML. If Tailwind handles all component styling, BEM adds overhead without benefit. If you write custom CSS alongside Tailwind for specific complex components, BEM is still a sound naming strategy for those styles.
With React and CSS Modules: CSS Modules scope class names to the component file automatically, solving the same global namespace problem BEM addresses. BEM's naming syntax is largely redundant in that setup, though the thinking behind it (separating block/element/modifier concerns) still helps structure your CSS rules.
With plain CSS or Sass on a multi-developer project: BEM is as relevant in 2026 as it was in 2015. Global stylesheets still need a naming system, and BEM remains the clearest one available.
When not to use BEM
BEM is designed for component-level CSS. It is not the right tool for:
- Base/reset styles - rules applied directly to HTML elements (
body,h1,p) do not need BEM class names - Layout utilities - single-purpose classes like
.container,.grid, or.flex-centerused across many unrelated components - Third-party plugin markup - when a library generates its own HTML, you cannot control the class names it produces
- Small, single-developer projects - the overhead of BEM naming scales with team size and codebase complexity. A personal project does not need it.
Build with structure from the start
CSS debt accumulates fast. Style changes are hard to scope and easy to break. Starting a project with BEM costs almost nothing; retrofitting it onto an undisciplined stylesheet costs days.
The pattern is straightforward: name top-level components as blocks, name their internal parts as elements with __, and use -- modifiers for variations. Keep class names flat, purpose-driven, and free of appearance descriptors.
FAQs
1, What is BEM in CSS?
BEM stands for Block, Element, Modifier. It is a CSS naming methodology that structures class names to reflect component relationships. A block is a standalone component (.btn), an element is a child of that block (.btn__text), and a modifier is a variation in appearance or state (.btn--primary). BEM makes class names self-documenting and prevents naming collisions in shared stylesheets.
2, What is the correct BEM modifier syntax?
The community-standard BEM modifier syntax uses a double hyphen: .block--modifier and .block__element--modifier. The original Yandex documentation uses a single underscore, but the double-hyphen convention is used by CSS-Tricks, getbem.com, and the majority of frontend teams because it is visually distinct from multi-word block names that use single hyphens (.search-form).
3, Can you nest elements inside elements in BEM?
No. BEM elements always reference their block directly in the class name, regardless of HTML depth. .main-content__title is correct even if the h2 is nested inside a .main-content__wrapper div. Writing .main-content__wrapper__title breaks BEM convention and makes class names harder to refactor.
4, Can modifiers stand alone in BEM?
No. A modifier is always applied alongside the base block or element class: <button class="btn btn--primary">. Without the base .btn class, the element has no base styles to modify. The modifier only overrides or extends.
5, What is the difference between BEM, OOCSS, and SMACSS?
BEM is a naming convention that makes component relationships explicit in the class name. OOCSS separates structure from skin to promote reuse but does not prescribe naming. SMACSS provides a file organization system with five style categories but leaves naming to the team. Many projects combine SMACSS file organization with BEM naming.
6, Should I use BEM with Tailwind CSS or React?
If Tailwind or CSS Modules handles all your component styling, BEM's naming syntax is unnecessary because scoping is already handled. If you write custom global CSS alongside these tools, BEM remains useful for naming those styles. For plain CSS or Sass on multi-developer projects, BEM is still the clearest naming system available.