BEM (Block, Element, Modifier) is a component-based approach to web development. The idea behind it is to divide the user interface into independent blocks. This makes interface development easy and fast even with a complex UI, and it allows reuse of existing code without copying and pasting.
A functionally independent page component that can be reused. In HTML, blocks are represented by the class
attribute.
Features:
- The block name describes its purpose ("What is it?" —
menu
orbutton
), not its state ("What does it look like?" —red
orbig
).
Example
<!-- Correct. The `error` block is semantically meaningful -->
<div class="error"></div>
<!-- Incorrect. It describes the appearance -->
<div class="red-text"></div>
- The block shouldn't influence its environment, meaning you shouldn't set the external geometry (margin) or positioning for the block.
- You also shouldn't use CSS tag or
ID
selectors when using BEM.
This ensures the necessary independence for reusing blocks or moving them from place to place.
- Blocks can be nested in each other.
- You can have any number of nesting levels.
Example
<!-- `header` block -->
<header class="header">
<!-- Nested `logo` block -->
<div class="logo"></div>
<!-- Nested `search-form` block -->
<form class="search-form"></form>
</header>
A composite part of a block that can't be used separately from it.
Features:
- The element name describes its purpose ("What is this?" —
item
,text
, etc.), not its state ("What type, or what does it look like?" —red
,big
, etc.). - The structure of an element's full name is
block-name__element-name
. The element name is separated from the block name with a double underscore (__
).
Example
<!-- `search-form` block -->
<form class="search-form">
<!-- `input` element in the `search-form` block -->
<input class="search-form__input">
<!-- `button` element in the `search-form` block -->
<button class="search-form__button">Search</button>
</form>
- Elements can be nested inside each other.
- You can have any number of nesting levels.
- An element is always part of a block, not another element. This means that element names can't define a hierarchy such as
block__elem1__elem2
.
Example
<!--
Correct. The structure of the full element name follows the pattern:
`block-name__element-name`
-->
<form class="search-form">
<div class="search-form__content">
<input class="search-form__input">
<button class="search-form__button">Search</button>
</div>
</form>
<!--
Incorrect. The structure of the full element name doesn't follow the pattern:
`block-name__element-name`
-->
<form class="search-form">
<div class="search-form__content">
<!-- Recommended: `search-form__input` or `search-form__content-input` -->
<input class="search-form__content__input">
<!-- Recommended: `search-form__button` or `search-form__content-button` -->
<button class="search-form__content__button">Search</button>
</div>
</form>
The block name defines the namespace, which guarantees that the elements are dependent on the block (block__elem
).
A block can have a nested structure of elements in the DOM tree:
Example
<div class="block">
<div class="block__elem1">
<div class="block__elem2">
<div class="block__elem3"></div>
</div>
</div>
</div>
However, this block structure is always represented as a flat list of elements in the BEM methodology:
Example
.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}
This allows you to change a block's DOM structure without making changes in the code for each separate element:
Example
<div class="block">
<div class="block__elem1">
<div class="block__elem2"></div>
</div>
<div class="block__elem3"></div>
</div>
The block's structure changes, but the rules for the elements and their names remain the same.
An element is always part of a block, and you shouldn't use it separately from the block.
Example
<!-- Correct. Elements are located inside the `search-form` block -->
<!-- `search-form` block -->
<form class="search-form">
<!-- `input` element in the `search-form` block -->
<input class="search-form__input">
<!-- `button` element in the `search-form` block -->
<button class="search-form__button">Search</button>
</form>
<!--
Incorrect. Elements are located outside of the context of
the `search-form` block
-->
<!-- `search-form` block -->
<form class="search-form">
</form>
<!-- `input` element in the `search-form` block -->
<input class="search-form__input">
<!-- `button` element in the `search-form` block-->
<button class="search-form__button">Search</button>
An element is an optional block component. Not all blocks have elements.
Example
<!-- `search-form` block -->
<div class="search-form">
<!-- `input` block -->
<input class="input">
<!-- `button` block -->
<button class="button">Search</button>
</div>
If a section of code might be reused and it doesn't depend on other page components being implemented.
If a section of code can't be used separately without the parent entity (the block).
The exception is elements that must be divided into smaller parts – subelements – in order to simplify development. In the BEM methodology, you can't create elements of elements. In a case like this, instead of creating an element, you need to create a service block.
An entity that defines the appearance, state, or behavior of a block or element.
Features:
- The modifier name describes its appearance ("What size?" or "Which theme?" and so on —
size_s
ortheme_islands
), its state ("How is it different from the others?" —disabled
,focused
, etc.) and its behavior ("How does it behave?" or "How does it respond to the user?" — such asdirections_left-top
). - The modifier name is separated from the block or element name by a single underscore (
_
).
-
Used when only the presence or absence of the modifier is important, and its value is irrelevant. For example,
disabled
. If a Boolean modifier is present, its value is assumed to betrue
. -
The structure of the modifier's full name follows the pattern:
block-name_modifier-name
block-name__element-name_modifier-name
Example
<!-- The `search-form` block has the `focused` Boolean modifier -->
<form class="search-form search-form_focused">
<input class="search-form__input">
<!-- The `button` element has the `disabled` Boolean modifier -->
<button class="search-form__button search-form__button_disabled">Search</button>
</form>
-
Used when the modifier value is important. For example, "a menu with the
islands
design theme":menu_theme_islands
. -
The structure of the modifier's full name follows the pattern:
block-name_modifier-name_modifier-value
block-name__element-name_modifier-name_modifier-value
Example
<!-- The `search-form` block has the `theme` modifier with the value `islands` -->
<form class="search-form search-form_theme_islands">
<input class="search-form__input">
<!-- The `button` element has the `size` modifier with the value `m` -->
<button class="search-form__button search-form__button_size_m">Search</button>
</form>
<!-- You can't use two identical modifiers with different values simultaneously -->
<form class="search-form
search-form_theme_islands
search-form_theme_lite">
<input class="search-form__input">
<button class="search-form__button
search-form__button_size_s
search-form__button_size_m">
Search
</button>
</form>
From the BEM perspective, a modifier can't be used in isolation from the modified block or element. A modifier should change the appearance, behavior, or state of the entity, not replace it.
Example
<!--
Correct. The `search-form` block has the `theme` modifier with
the value `islands`
-->
<form class="search-form search-form_theme_islands">
<input class="search-form__input">
<button class="search-form__button">Search</button>
</form>
<!-- Incorrect. The modified class `search-form` is missing -->
<form class="search-form_theme_islands">
<input class="search-form__input">
<button class="search-form__button">Search</button>
</form>
Why write the block name in the names of modifiers and elements?
A technique for using different BEM entities on a single DOM node.
Mixes allow you to:
- Combine the behavior and styles of multiple entities without duplicating code.
- Create semantically new UI components based on existing ones.
Example
<!-- `header` block -->
<div class="header">
<!--
The `search-form` block is mixed with the `search-form` element
from the `header` block
-->
<div class="search-form header__search-form"></div>
</div>
In this example, we combined the behavior and styles of the search-form
block and the search-form
element from the header
block.
This approach allows us to set the external geometry and positioning in the header__search-form
element, while the search-form
block itself remains universal.
As a result, we can use the block in any other environment, because it doesn't specify any margin. This is why we can call it independent.
The component approach adopted in the BEM methodology also applies to projects in the file structure. The implementations of blocks, elements, and modifiers are divided into independent technology files, which means we can connect them individually.
Features:
- A single block corresponds to a single directory.
- The block and the directory have the same name. For example, the
header
block is in theheader/
directory, and themenu
block is in themenu/
directory. - A block's implementation is divided into separate technology files. For example,
header.css
andheader.js
. - The block directory is the root directory for the subdirectories of its elements and modifiers.
- Names of element directories begin with a double underscore (
__
). For example,header/__logo/
andmenu/__item/
. - Names of modifier directories begin with a single underscore (
_
). For example,header/_fixed/
andmenu/_theme_islands/
. - Implementations of elements and modifiers are divided into separate technology files. For example,
header__input.js
andheader_theme_islands.css
.
Example
search-form/ # Directory of the `search-form`
__input/ # Subdirectory of the `search-form__input`
search-form__input.css # CSS implementation of the
# `search-form__input` element
search-form__input.js # JavaScript implementation of the
# `search-form__input` element
__button/ # Subdirectory of the `search-form__button`
# element
search-form__button.css
search-form__button.js
_theme/ # Subdirectory of the `search-form_theme`
# modifier
search-form_theme_islands.css # CSS implementation of the `search-form` block
# that has the `theme` modifier with the value
# `islands`
search-form_theme_lite.css # CSS implementation of the `search-form` block
# that has the `theme` modifier with the value
# `lite`
search-form.css # CSS implementation of the `search-form` block
search-form.js # JavaScript implementation of the
# `search-form` block
This file structure makes it easy to support the code and re-use it.
The branched file structure assumes that in production the code will be assembled into shared project files.
You aren't required to follow the recommended file structure. You can use any alternative project structure that follows the BEM principles for organizing the file structure, such as: