_bemify

A set of Sass mixins to write well-structured, maintainable, idiomatic BEM-style .scss source:

@include block('name') {
  …
 
  @include element('child') {
    …
  }
 
  @include modifier('light') {
    …
  }
 
  @include state('active') {
    …
  }
 
}
 .name {
  …
}
  
.name__child {
  …
}
 
.name--light {
  …
}
 
.name.is-active {
  …
}
  

Install

Bemify can be installed as a Ruby Gem, NPM-module, via bower, or manually. As a NPM module, bemify supports eyeglass. Bemify is also on Sache.

Ruby Gem

$ gem install bemify

NPM

$ npm install bemify --save-dev

Bower

$ bower install bemify

Manual Install

Clone the repository or download sass/_bemify.scss. Put _bemify.scss in the directory of your sass/scss code where you deem fit.

Using bemify

First, import bemify (note that the path might need to be adjusted depending on your installation method):

@import "bemify";

Then you can use bemify to write bem-style scss source for your components. The output will be full, non-nested bem-style class selectors.

@include block('my-block') {
  …
 
  @include element('child') {
    …
  }
 
  @include modifier('small') {
    …
  }
 
  @include state('state') {
    …
  }
 
}
 .my-element {
  …
}
 
.my-element__child {
  …
}
 
.my-element--small {
  …
}
 
.my-element.is-active {
  …
}
 

By default, bemify will output combined .block.state / .block__element.state selectors. Bemify can also be configured to output full .block--state / .block__element--state selectors. For details, see Configuration below.

Nesting

The mixins can be nested to create modifiers for subcomponents:

@include block('my-element') {
 
  @include element('child') {
    …
 
    @include modifier('bad') {
      …
  
      @include state('happy') {
        …
      }
 
    }
 
  }
 
  @include modifier('large') {
    …
  }
 
  @include state('active') {
    …
  }
 
}
 .my-element {
  …
}
 
.my-element__child {
  …
}
 
.my-element__child--bad {
  …
}
 
.my-element__child--bad.is-happy {
  …
}
 
.my-element--large {
  …
}
 
.my-element.is-active {
  …
}
 

Scoping

Bemifys mixins can be used inside a scope. Whether scoping is to be considered true BEM remains open for dicsussion though.

.scope {
  
  @include block('my-block') {
    …
    
    @include element('item') {
      …
    }
  
  }  
 
}
 .scope .my-block {
  …
}
 
.scope .my-block__item {
  …
}
 

Configuration

Bemify uses configuration variables to adjust the block-element and block-/block-element-state separator, as well as the state prefix. To overwrite bemify's config with your own configuration file, just import your variables before using one of the mixins.

@import "my_config";
@import "bemify";
  
@include block('my-block') {
  …
}
 

If you are not using a configuration file, you can directly override the appropriate variables after importing bemify. The configuration variables and their defaults are:

  • $combined-state-selectors: true

    true will ouput .block.is-active, false will output .block--is-active.

  • $element-separator: __
  • $modifier-separator: --
  • $state-prefix: is

Note that $state-prefix can be overridden with each call to the state mixin as a second argument, so you can use both --is-active and --has-error using the same configuration:

@include state('error', 'has') {
  …  
}
 

Aliases

Not everyone thinks in the categories of 'block, element, modifier', but many of us still want to write modularized, component-based CSS. There are a couple of aliases included for those who think in terms of components, parent-child / -subcomponents included.

@include block('name') {}
== @include component('name') {}
 
@include element('name') {}
== @include child('name') {}
== @include subcomponent('name') {}
== @include sub('name') {}
 

It is also straightforward to add your own aliases:

@mixin my-block-alias($name) {
  @include block($name) {
    @at-content;
  }
}