BEM: Self-Documenting CSS Class Names
BEM turns classes into a mini filesystem: Block__Element--Modifier. It prevents CSS collisions in large React codebases where many teams share a global stylesheet. The footgun is turning every nested tag into an element and creating comically long names.
Why it exists
CSS is global by default. When two developers on the same React app write .title or .active, the last one loaded wins and bugs appear at runtime without type errors or build failures. BEM was created to solve this namespace collision problem without requiring JavaScript tooling. By baking the component name into every class, it creates cheap, human-readable scoping that works in any browser and any build pipeline.
The mental model
Think of your interface as a set of LEGO blocks. A Block is a standalone thing like a Button or a Card. An Element is a piece that only belongs inside that block, like a Button's icon or a Card's title. A Modifier is a variant, like a primary Button or a featured Card. The class name itself tells you which block owns the element and whether it is a variant, so the HTML becomes self-documenting.
How it works
The syntax is strictly BlockElement--Modifier. The double underscore means belongs to. The double hyphen means looks different. For example, a search form might use .search-form, .search-forminput, and .search-form--compact. You write these as flat single classes in CSS, which keeps specificity low and avoids the specificity wars caused by deep selectors. If an element needs its own state, you attach the modifier to it, like .search-forminput--error. Every word is lowercase and separated by a single hyphen, so multi-word blocks become .user-profileavatar--large.
When to use it
Reach for BEM in React or Next.js when you are using plain CSS, Sass, or CSS Modules and you want naming conventions that survive code review without extra dependencies. It is especially valuable in design systems and component libraries where many engineers touch the same stylesheets. Because the convention is visible in the DOM, debugging in browser DevTools is immediate: you see a class and you know exactly which file to open.
When not to use it
Do not use BEM inside Tailwind or utility-first workflows, because utility classes already encode scope through composition and BEM names would only add noise. It also fights against CSS-in-JS libraries like styled-components or Emotion, where the component name lives in the JavaScript and the library hashes classes for you. Finally, avoid turning every nested div into an element; if a component has its own independent meaning, promote it to a new block rather than chaining three underscores.
One canonical example
Imagine a Next.js page with a ProductCard React component. Its JSX contains a root div with class product-card, an image with class product-cardimage, a title with class product-cardtitle, and a modifier class product-card--on-sale applied to the root when discounted. The CSS lives in ProductCard.module.css or a co-located Sass file. Six months later, another developer sees product-cardtitle in the DOM and knows instantly that the style lives in the ProductCard stylesheet, cannot collide with a ReviewCardtitle, and that product-card--on-sale is a state variant rather than a separate component.
Interview question
A code review reveals the class product-card__header__title__link. What does BEM suggest is wrong with this naming?
- a.It should include a modifier to indicate the link variant
- b.It will cause a specificity war in the stylesheet
- c.Multi-word names should use single hyphens, not underscores
- d.It chains too many elements instead of promoting independent blocksCorrect
Why? this is the answer
BEM warns against turning every nested tag into an element and creating comically long names; independent pieces should be promoted to new blocks. Option B is tempting because BEM mentions specificity wars, but those are caused by deep selectors, not by long BEM names themselves.
Just read this? Test yourself on what you have been reading.
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Every open role lists the topics its interview covers, so you can prepare for the real thing rather than guessing.
See open roles