BEM Grandchildren: How To Handle Deeply Nested Elements

January 21, 2020

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).

Russian dolls are a good representation of 'Grandchild' elements in BEM Nesting in BEM is not as scary as these Russian dolls

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 The 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 become a BEM pro.

    I'll never send you spam. Unsubscribe at any time.

    Tom Ray

    By Tom Ray, a front-end developer who lives in London with his fiancée and cat Arnold.

    © Scalable CSS 2020, built with ❤️ in London, UK.