Skip to content

Creating a Module

esr360 edited this page Jan 17, 2020 · 49 revisions

Naming Convention (HTML/CSS)

Please read the Cell Naming Convention page for full context before reading this guide.

Basic Usage

To generate styles for a module, simply call the Module mixin with your desired arguments.

@include module('button') {
  display: block;
}
CSS Output
.button, 
[class*="button--"] {
  display: block;
}
Corresponding HTML
<div class="button">Button</div>

Components

@include module('header') {
  @include component('menu') {
    float: left;
  }
}
CSS Output
.header__menu, 
[class*="header__menu--"] {
  float: left;
}
Corresponding HTML
<div class="header">
  <div class="header__menu">
      ...
  </div>
<div>

Sub-Components

As with BEM, nesting Components can be confusing, awkward, and complex, and should be avoided where possible. However, it is possible by using the sub-component() mixin.

Take the following example of a Cell Sub-Component:

<div class="header">
  <ul class="header_menu">
    <li class="header_menu_item">...</li>
    <li class="header_menu_item">...</li>
    <li class="header_menu_item">...</li>
  </ul>
</div>

The elements with the header_menu_item class in the above example would be considered Sub-Components, and represented by Cell as:

@include module('header') {
  @include component('menu') {
    @include sub-component('item') {
      ...
    }
  }
}

Without using sub-components, you might think to do the same thing like this (which wouldn't work as expected):

@include module('header') {
  @include component('menu') {
    @include component('item') {
      ...
    }
  }
}

...which would actually be equivalent to:

@include module('header') {
  @include component('item') {
    ...
  }
}

In this particular exmaple, the recommendation would probably be to make menu its own module, and have item be a regular component of that module; but sometimes Sub-Components are difficult to avoid.

Modifiers

Modifiers can be added to modules, components and sub-components, and can be created by using the Modifier/Is mixins.

@include module('header') {
  @include is('fixed') {
    position: sticky;
  }

  @include component('menu') {
    @include is('small') {
      font-size: 0.85em;
    }

    @include sub-component('item') {
      @include is('special') {
        background-color: pink;
      }
    }
  }
}
CSS Output
[class*="header--"][class*="--fixed"] {
  position: sticky;
}

[class*="header__menu--"][class*="--small"] {
  font-size: 0.85em;
}

[class*="header__menu__item--"][class*="--special"] {
  background-color: pink;
}
Corresponding HTML
<div class="header--sticky">
  <div class="header__menu--small">
    <div class="header__menu__item">...</div>
    <div class="header__menu__item--special">...</div>
    <div class="header__menu__item">...</div>
  </div>
  ...
</div>

Nested Modifiers

Modifiers can be nested should you need to style an element when more than one modifier is applied:

@include module('myModule') {
  @include modifier('someModifier') {
    @include modifier('anotherModifier') {
      background-color: green;
    }
  }
}
CSS Output
[class*="myModule--"][class*="--someModifier"][class*="--anotherModifier"] {
  background-color: green;
}
Corresponding HTML
<div class="myModule--someModifier--anotherModifier">...</div>

Nesting Modules

Consider a project with separate header and menu modules. We may wish to apply custom styles to the menu module when it is inside the header module. This can be done in two ways.

Cascading/Nesting (inside header.scss)
@include module('header') {
  @include module('menu') {
    @include component('item') {
      display: inline-block;
    }
  }
}
Using Context (inside menu.scss)

See the Context mixin for more information

@include module('menu') {
  @include context('header') {
    @include component('item') {
      display: inline-block;
    }
  }
}

...or:

@include module('menu') {
  @include component('item') {
    @include context('header') {
      display: inline-block;
    }
  }
}
CSS Output

The output is the same for all examples

.header .menu__item, 
.header [class*="menu__item--"], 
[class*="header--"] .menu__item, 
[class*="header--"] [class*="menu__item--"] {
  display: inline-block;
}

Creating a Module Mixin

In case you need to call a module multiple times with different configurations to generate separate sets of CSS, you can create your module within a mixin.

Note that if you use JavaScript for theming and configuration this section will likely not apply to you, otherwise the approach outlined in this section is recommended

First let's take a base module with some configuration as an example (read the Module Configuration page for more information):

Configuraton properties which correspond to CSS properties (e.g. font-size and background-color) do not need to be hard coded into the module's source

$config: (
  'name': 'myModule',
  'font-size': 20px,
  'background-color': #0155a0
);

@include module {
  display: flex;
  position: relative;
  cursor: pointer;
}

Let's say we want to use the core of this module to create two different modules with different names and different configurations passed to them to give a different look and feel. This can be done by

  • Wrapping the above code in a mixin
  • Passing a $custom parameter to the mixin
  • Calling the create-config() utility function passing the module's default configuration and the $custom argument
  • ...and assiging the result to the $config variable
@mixin myModule($custom: ()) {
  $config: create-config((
    'name': 'myModule',
    'font-size': 20px,
    'background-color': #0155a0
  ), $custom);

  @include module {
    display: flex;
    position: relative;
    cursor: pointer;
  }
}

Now to generate the default CSS for this module you would call the mixin:

@include myModule;
CSS Output
.myModule, [class*="myModule--"] {
  font-size: 20px;
  background-color: #0155a0;
  display: flex;
  position: relative;
  cursor: pointer;
}

To call the module with a different configuration set, pass the new values when calling the mixin:

@include myModule((
  'name': 'somethingElse',
  'font-size': 16px,
  'background-color': #444444,
  'text-align': center
));
CSS Output
.somethingElse, [class*="somethingElse--"] {
  font-size: 16px;
  background-color: #444444;
  text-align: center;
  display: flex;
  position: relative;
  cursor: pointer;
}