The Component, Element, Modifier pattern increases the reusability and maintainability of CSS code by scoping CSS styles to particular components through the use of class naming conventions.
Problem
CSS can easily get out of hand on large projects if not managed properly. As a project grows, often so does the length of selectors—creating ongoing specificity wars in which one style overrides another which overrides another and so on and so on. The resulting over-specified selectors make these styles nearly impossible to reuse as they become more and more tightly coupled to the HTML in which they were originally styled. This leads to fragile styles and unpredictable results when future changes need to be made.
Solution
The Component, Element, Modifier pattern helps mitigate these issues of over-specified selectors and style contamination through naming conventions—making styles more modular and reusable. This pattern aims to reduce specificity across selectors, instead relying on unique class names to scope styles to DOM elements.
Note 'reduce' not 'eliminate' specificity. Specificity and the cascade are essential tools in the CSS developer's toolbox. The goal is not to get rid of them, just manage them better.
Traditional programming languages implement some sort of scope that prevents variables from getting cross contaminated. CSS is not a programming language. It is a stylesheet language. It does not have variable scope. Instead, scope refers to the elements for which a given ruleset applies. In CSS, scope is controlled by selectors and the cascade. The selector p { … }
is scoped to all paragraph tags. .nav > li { … }
is scoped to all li elements that are direct descendants of elements with the nav
class.
Component
A component is an independent chunk of styled HTML that can be added to any region of a page while maintaining its visual style. The outer most wrapping element of a component is refered to as the Base Component. It includes a CSS class named after the component itself. This is referred to as the Base Class. For example: a search component might have a base class of search
.
Element
Elements are the individual HTML elements that are combined to create a component. Each element includes a CSS class which is a derivative of the base class name. For example: a search component has an input field with a class of search__input
and a submit button with the class of search__button
.
Modifier
Modifiers are classes that alter the appearance of the base component by adding additional styles or overriding the base component's defaults. Modifiers are typically named after the base component, however certain types of modifiers can use their own naming conventions, for instance the state classes in SMACSS.
For clarity, choose a different naming convention than that used for elements so modifiers and elements are easily distinguishable. For example: a search component might have a modifier class of search--inline
which sets the input and button on a single line as opposed to the default stacked layout.
In most cases a modifier is applied via additional classes added to the base component. In some cases a modifier may be applied via a CSS preprocessor such as SASS's extend directives.
Example
<br /> <ul class="nav"><br /> <li class="nav__item"><br /> <a class="nav__link" href="/" >Home</a><br /> </li><br /> <li class="nav__item"><br /> <a class="nav__link" href="/about" >About</a><br /> </li><br /> <li class="nav__item"><br /> <a class="nav__link" href="/contact">Contact</a><br /> </li><br /> </ul><br />
In the above example of navigation markup;
nav
is the base component class; nav__item
and nav__link
are element classes and nav--inline
is the modifier class.
Sub-Components
Components nested within a larger component are referred to as sub-components. These may or may not follow the same naming conventions as elements of the larger component. However, sub-components are still components and their appearance should remain independent of their location within their parent component.
CSS Source Order
Due to the more level playing field the class based selectors are on, greater attention to CSS source order is needed. With all others things equal, selectors appearing later in the stylesheet will override those appearing before. Always group your component styles together in your stylesheet with base component definitions first and modifiers that should take precedence last.
Examples in Use
The Component, Element, Modifier pattern has been made popular in recent years with the release of SMACSS by Jonathon Snook. Similar solutions can be found in other CSS architectures and front-end frameworks. The following are examples of varying implementations of the same basic pattern.
A Note on Design Patterns
Design patterns are common solutions to recurring problems within a given context. Despite their name, design patterns are not designed, but observed. They are not step-by-step instructions. They represent the basic concepts required to solve a problem and can be implemented in different ways based on the use case and context.