Understanding the basic concept of BEM (block, element, and modifier) is a fairly simple concept to grasp.
However, things can start to easily go out of control when elements start to get 3 or 4 layers nested deep within a block.
Bonus: Download a free cheat sheet that will show you how to quickly get started with BEM.
These nested elements are typically known as 'grandchild' elements (as they're nested 2 levels deep).
In this article, I'll tackle how to solve these common issues and follow BEM best practices.
Ready? Let's dive in.
Chaining Elements Together - The Typical Grandchild Mistake
Here’s how many people solve for nesting elements within elements with BEM:
<div class=“nav”>
<ul class=“nav__menu”>
<li class=“nav__menu__item”>
<a class=“nav__menu__item__link”>Home</a>
</li>
</ul>
</div>
Following this method of chaining elements (like this: .nav__menu__item__link
) gets out of control pretty quickly.
It makes your class names difficult to read, not to mention it'll unnecessarily bloat your HTML and CSS files.
This approach also follows the structure of the DOM, which limits your flexibility if the structure of your HTML changes.
Don't just take my word for it. Vladimir Grinenko is on the Yandex team (the creators of the BEM methodology) and said this:
"BEM methodology doesn't recommend to use elements within elements in class names. You don't need to resemble DOM structure in naming. Having one level structure makes refactoring much easier."
— Vladimir Grinenko, Yandex
For example, imagine that you realised that you needed to add a <div>
inside the <nav>
:
<div class=“nav”>
<div class="nav__wrapper"> <!-- Here is my new div-->
<!-- Now I need to refactor all the classes below
because of the new div -->
<ul class=“nav__wrapper__menu”>
<li class=“nav__wrapper__menu__item”>
<a class=“nav__wrapper____menu__item__link”>Home</a>
</li>
</ul>
<div>
</div>
All the classes within the <div>
would need to be updated, as well as updating the class names in your CSS file.
So as you can see, taking the Block__Element__Element__Element
is not a long term, sustainable choice.
Here's how to better solve it:
The Grandchild Solution
Instead of chaining elements like nav__menu__item__link
, simply focus on the block name itself and use that as the main anchor:
<div class=“nav”>
<ul class=“nav__menu”>
<li class=“nav__item”>
<a class=“nav__link”>Home</a>
</li>
</ul>
</div>
Taking this approach also makes your code much more readable for other developers, as they can easily see all the elements that have a relationship with the block (in this case: .nav
).
And if you need to add or remove HTML elements in the future, no refactoring is required:
<div class=“nav”>
<!-- New div added without the need to refactor -->
<div class="nav__wrapper">
<ul class=“nav__menu”>
<li class=“nav__item”>
<a class=“nav__link”>Home</a>
</li>
</ul>
</div>
</div>
If you find yourself entering territory where your elements are more than 3 levels deep, you might need to reconsider the structure of the block, potentially even breaking the block into smaller chunks.
And that's it!
I hope this article has helped you solve the 'Grandchild' scenario moving forward.
Download Free BEM Cheat Sheet
Want to start practicing BEM and looking for a no-nonsense, quick start action guide?
Download a free cheat sheet covering BEM basics so you can dive in and start practicing today.
Top comments (2)
Nesting is the devils anus in my opinion/experience.
And grandchildren is just another way to do it. :)
So I totally agree, if you have to BEM, at least scale it as horizontally as possible. :)
Nesting can indeed be super annoying.
Glad you agree and enjoyed the article!