Battling BEM: 10 Common Problems And How To Avoid Them

A practical guide to mastering BEM CSS methodology, solving real-world naming and styling challenges in modern web development.

The Case for BEM in Modern Web Development

Whether you've just discovered BEM or are an old hand in web terms, you probably appreciate what a useful methodology it is. BEM (Block Element Modifier) has been an absolute lifesaver for developers creating applications in a modular, component-driven way.

One of the things that puts developers off adopting BEM is how eye-gougingly ugly the syntax is. The designer in many of us doesn't want markup cluttered with double underscores and foul double hyphens. But the developer perspective looks at it pragmatically: the logical, modular way of building a user interface outweighs aesthetic concerns.

BEM addresses real challenges in large-scale CSS development, from name collisions to component isolation. This guide covers the 10 most common challenges developers face with BEM and provides practical solutions for each. For more foundational CSS techniques, explore our comprehensive guide.

Problem 1: What To Do About "Grandchild" Selectors?

To clarify, you would use a grandchild selector when referencing an element nested two levels deep. These are the bane of many developers' existence, and their misuse is one of the reasons people have an immediate aversion to BEM.

The wrong approach:

<div class="c-card">
 <div class="c-card__header">
 <h2 class="c-card__header__title">Title text here</h2>
 </div>
</div>

The BEM approach:

<div class="c-card">
 <div class="c-card__header">
 <h2 class="c-card__title">Title text here</h2>
 </div>
</div>

BEM stands for Block-Element-Modifier, not Block-Element-Element-Modifier. The double underscore should appear only once in a selector name. BEM naming isn't strictly tied to the DOM structure--elements at any nesting level use the same flat naming convention.

As explained in Smashing Magazine's comprehensive guide to BEM challenges, this flattening principle applies to all descendant elements regardless of their depth in the markup hierarchy.

Problem 2: Should I Be Namespacing?

Namespacing improves code readability by categorizing classes based on their purpose. This technique, popularized by Harry Roberts, uses prefixes to distinguish between different types of classes.

TypePrefixExamplesDescription
Componentc-.c-card, .c-menuStandalone UI components with cosmetics
Layoutl-.l-grid, .l-containerPosition-only modules, no cosmetics
Helperh-.h-clearfix, .h-showUtility classes, often with !important
Stateis-, has-.is-active, .has-loadedTransient states controlled by JavaScript
JavaScriptjs-.js-tab-switcherBehavior hooks only, no styling

Using these namespaces makes code infinitely more readable. Even if BEM itself isn't for you, namespacing is a valuable practice to adopt. The CSS Wizardry namespacing approach has become an industry standard for organizing CSS class purposes.

Problem 3: What Should I Name Wrappers?

Some components require a parent wrapper or container for layout purposes. The temptation is to create a component wrapper, but this often leads to unnecessary complexity.

The solution: Abstract layout into layout modules and keep components pure.

<ul class="l-grid">
 <li class="l-grid__item">
 <div class="c-card">
 <div class="c-card__header">...</div>
 <div class="c-card__body">...</div>
 </div>
 </li>
</ul>

When you truly need a semantic wrapper (not just for layout), use words like container or list with the layout prefix: l-cards-container or l-cards-list. The key is consistency with your naming convention. This separation mirrors how our web development services approach component architecture--keeping concerns distinct and modular.

For a deeper dive into grid-based layouts, see our guide on understanding CSS Grid. Layout modules should handle positioning and structure, while components handle their internal styling independently.

Problem 4: Cross-Component... Components?

A common challenge is styling a component differently based on its parent container. The BEM solution is the mix pattern--hosting multiple entities on the same DOM node.

<button class="c-button c-button--primary articles__buy-button">
 Buy Now
</button>
  • .c-button provides base button styles
  • .c-button--primary provides the primary variant
  • .articles__buy-button provides context-specific overrides

This approach combines reusable component styles with parent-specific styling without creating tight coupling between components. The BEM mix entity pattern allows you to leverage the benefits of multiple methodologies simultaneously while maintaining clear separation of concerns.

Mixes are particularly valuable when integrating components into different contexts across your application, whether in a sidebar, main content area, or modal dialog.

Problem 5: What About JavaScript?

Never tie JavaScript behavior to styling classes. When you do, refactoring styles can break functionality, and vice versa.

The solution: Use the js- prefix for JavaScript hooks only.

<button class="c-button c-button--primary js-modal-trigger" data-modal="signup">
 Sign Up
</button>
  • c-button = styling
  • c-button--primary = variant styling
  • js-modal-trigger = JavaScript hook only

This separation of concerns means your JavaScript team can work without breaking CSS, and your CSS team can refactor without breaking JavaScript. When working with modern frontend frameworks, this pattern becomes especially valuable as CSS architecture and JavaScript logic often evolve at different paces.

The js- prefix serves as a clear signal to developers that modifying these classes may break interactive functionality, protecting critical user experiences.

Problem 6: What Do I Name State Modifiers?

States are transient conditions controlled by JavaScript (like dropdown open/closed). Variants are persistent characteristics (like a featured card).

Use is- and has- for states:

  • .is-open -- dropdown is open
  • .is-active -- tab is active
  • .has-loaded -- content has finished loading

Use -- modifiers for variants:

  • .card--featured -- persistent featured style
  • .button--large -- size variant
  • .menu--horizontal -- orientation variant

The difference matters: States come and go with user interaction. Variants are defined at design time and remain constant. This distinction helps maintain clean, predictable CSS that scales well as your application grows and user interfaces become more complex.

Problem 7: Mixing BEM with Other Approaches

Many teams use BEM alongside utility-first frameworks like Tailwind CSS. This hybrid approach works when you establish clear boundaries.

BEM for components:

<div class="c-card c-card--featured">
 <h2 class="c-card__title">Featured Article</h2>
 <p class="c-card__content">Content goes here...</p>
</div>

Hybrid approach:

<div class="c-card p-6 bg-white rounded-lg">
 <h2 class="c-card__title text-xl font-bold">Title</h2>
</div>

Guidelines for hybrid approaches:

  • Use utilities for spacing, colors, typography
  • Use BEM for structural and behavioral patterns
  • Document team conventions clearly
  • Apply consistently within components

As noted by the DEV Community on hybrid CSS approaches, the key to success is consistency rather than ideological purity. For more advanced CSS techniques, explore our detailed guides.

Problem 8: Component Reuse Without Side Effects

BEM's core principle is isolation. Components should work independently without relying on parent selectors.

Avoid cascade selectors that create hidden dependencies:

/* Bad: Creates dependency on parent */
.sidebar .c-card { }

/* Good: Block is self-contained */
.c-card { }

The independence principle:

  • Each block should work in any context
  • No assumptions about parent elements
  • Layout handled by layout modules, not parent selectors
  • Move components freely without style breakage

The BEM methodology's emphasis on component isolation ensures that your components remain portable and reusable across different projects and contexts. This independence is crucial for maintaining scalable CSS architecture as applications grow. Understanding CSS float theory and layout history helps appreciate why BEM's isolation principle is so important.

Problem 9: Multi-Word Naming Conventions

Consistency in multi-word names prevents confusion and maintains readability.

Use kebab-case throughout:

  • .c-search-button -- not .c_searchButton
  • .c-user-profile-card -- not .cUserProfileCard
  • .c-main-navigation -- not .cMainNavigation

Naming decision tree:

  1. Is it a standalone component? → c- + block name
  2. Is it a part of that component? → __ + element name
  3. Is it a variant or state? → -- + modifier or is-/has- prefix
  4. Is it layout-only? → l- prefix

Pro tip: When in doubt, err on the side of longer, more descriptive names. c-user-profile-card is clearer than c-profile. Consistent naming becomes especially important in larger projects where multiple developers are contributing to the same codebase.

Problem 10: File and Folder Organization

Organize BEM projects by component, not by file type. This keeps related code together and makes navigation intuitive.

Component-based structure:

styles/
├── components/
│ ├── _button.scss
│ ├── _card.scss
│ └── _menu.scss
├── layout/
│ ├── _grid.scss
│ └── _container.scss
├── utilities/
│ └── _helpers.scss
└── main.scss

Block-centric alternative (recommended for large projects):

styles/
├── blocks/
│ ├── button/
│ │ ├── _button.scss
│ │ ├── _button--large.scss
│ │ └── _button--primary.scss
│ └── card/
│ ├── _card.scss
│ └── _card--featured.scss
└── main.scss

Benefits of block-centric organization:

  • Everything related to a block in one place
  • Easy to find and modify
  • Simple to copy blocks between projects
  • Scales well as project grows

As recommended by modern CSS organization strategies, the block-centric approach scales particularly well for enterprise applications with hundreds of components.

BEM Best Practices Quick Reference

One Level of Nesting

Block elements use single underscore: .block__element, never .block__element__element

Consistent Namespacing

Use c-, l-, h-, js-, is- prefixes categorically across all code

Separate Layout from Components

Use l- prefix for layout modules, c- for components

Use Mixes for Context

Combine multiple classes for parent-specific styling without coupling

JavaScript Hooks Separate

js- prefix means 'for JavaScript only'--never style these classes

States vs Variants

is-/has- for transient states, -- for persistent variants

Independent Blocks

Components work in any context, no parent selector dependencies

Kebab-Case Names

Multi-word names use kebab-case consistently: .user-profile-card

Organize by Component

Folder structure reflects component boundaries, not file types

Document Conventions

Write down your team's BEM conventions and reference them

Conclusion: BEM's Ugly Syntax Is Actually Beautiful

BEM's unconventional naming might not win beauty contests, but it solves real problems. The explicit structure--blocks, elements, and modifiers--creates self-documenting code that scales with your project.

The 10 problems covered here are common stumbling blocks, but they're surmountable with consistent application of BEM principles:

  1. Grandchild selectors → Flatten to single-level elements
  2. Namespacing → Use prefixes for clarity
  3. Wrapper naming → Separate layout from components
  4. Cross-component styling → Use mix patterns
  5. JavaScript hooks → Separate with js- prefix
  6. State modifiers → Use is-/has- for transient states
  7. Mixing approaches → Establish clear boundaries
  8. Component isolation → Create truly independent blocks
  9. Multi-word naming → Use kebab-case consistently
  10. File organization → Structure by component

Start with one component in your current project. Apply BEM principles consistently. Watch as specificity conflicts disappear and team collaboration improves. The awkward syntax becomes beautiful when you see the maintainability it enables.

Your next step: Pick one component from your current project and refactor it using BEM. Pay special attention to element naming and state management. Experience the difference that clear naming conventions make.

If you're building modern web applications, our team can help you implement scalable CSS architecture. Learn more about our frontend development services or contact us for a consultation on your specific needs.

Frequently Asked Questions

Ready to Level Up Your CSS Architecture?

Our web development team specializes in modern CSS methodologies including BEM, helping you build scalable, maintainable interfaces.