Search code examples
cssreactjssassbemreact-css-modules

Reactjs, Bem naming nested structure with SCSSModule


We are using SCSS, SCSSModule and BEM naming methodology. I have researched the best structure for nested elements. I've seen different syntaxes and still have question mark in my head. I saw the symbol differences, for example some teams use "block__element_modifier", some use "block__element--modifier". I know basic usage of BEM. We shouldn't nest the elements with multiple underscored syntax(block__element__nested is wrong). Currently we are using BEM like

block__element--modifier and nested elements are written with extra hyphen prefix.

Think that the card component structure like below

card
----header
----------title
----------subtitle
----body
----footer

and we code the sass like

// example.scss

.card {
   &__header {
      // some css
      &-title {
         // some css
      }
      &-sub-title {
         // some css
      }
   }
}

and its classes' output is:

card
card__header
card__header-title
card__header-subtitle

Most of the answers in stackoverflow and also some of articles don't suggest BEM as above. They suggest like this:

.card {
   &__header {
      // some css
   }
   &__title {
      // some css
   }
   &__sub-title {
      // some css
   }
}

and its output turn into this:

card
card__header
card__title
card__subtitle

But If I apply as in option 2, I can't figure out which element is in which when I only read scss file. On the other hand, we can understand that in the first option. But the disadvantage of the first option is that the elements become more dependent on each other. For example, when a new div comes between nested elements, I need to refactor related nested class names in the jsx file.

(But still think that it is very useful to understand which elements are nested in the scss file.)

The question is, is my BEM naming wrong or is there such a use in community?

Note: I said we use "module.scss" but I didnt give example in that format. I know, I didnt want to confuse with camelCase things in js.


Solution

  • Your naming is not wrong; it works and it satisfies the BEM pattern; but personally I would not recommend it, and would instead recommend the popular approach.

    Your current approach encodes the DOM nesting of elements into the class names. If you need to make changes with regard to the nesting -for example you need an additional wrapper somewhere, which from my experience is a rather common occurence- you will need to change all nested class names. I would be immensely annoyed by that. And a second drawback of your current approach is that it produces rather long class names.

    But what I think is really the biggest drawback of it: It forces you to nest your SCSS exactly like the DOM nesting to be able to build up the class names. This -in my opinion- makes the SCSS unnecessairily complicated. With the popular approach your nesting depth for the styles can stay shallow and therefore easier to handle by humans, without messing up the braces { } or needing to nest and unnest rules when the DOM structure changes.

    In one of my projects we started with your approach and later changed to the popular approach, and I experienced it as an improvement.

    One example:

    <div className="card">
      <div className="card__header">
        <div className="card__branding">
          <Logo className="card__logo" />
          <span className="card__brandname">Nutrax</span>
        </div>
        <h2 className="card__title">Recommendation for hard working web devs!<h2>
      <div>
      <div className="card__body">
        Try Nutrax for Nerves!
      <div>
      <div className="card__footer">
        <Button className="card__button">Find nearest store</Button>
        <Button className="card__button card__button--promoted">Buy online</Button>
      <div>
    </div>
    
    .card {
      &__header {}
      &__body {}
      &__footer {}
      &__branding {}
      &__logo {}
      &__brandname {}
      &__title {}
      &__button {
        &--promoted {}
      }
    }
    

    Now move the branding into the body, no problem, the changes are minimal, and you don't even need to change the SCSS.

    PS: You mentioned that you use SCSSModules; I'm not sure I understand what that means. I'm well aquainted with css-modules and I use them usually in my react projects, which completely removes the need for BEM and I can just use rather simple class names that will be automatically scoped to my component only. If that is also the case with SCSSModules in your project I don't see the need to apply BEM.