Theme Handbook Components

Layers

Components are grouped into four distinct layers:

(Definitions taken from Atomic Design, by Brad Frost, chapter 2.)

Benefits

Breaking themes into components has several benefits:

Trivial Components

But what about trivial components, like headings, hard rules, and links? Is it worth it to break out the styling for these components into separate files instead of simply keeping the styles in global.less?

There are still good reasons to use separate files for these basic components:

  1. Readability. Keeping the styling for each component in its own file keeps global.less from growing longer and longer over time, making it and the individual style files it imports easier to read and understand.

  2. Decoupling. Keeping the styling for each component in its own file prevents the styling for different components from becoming intertwined. When styling for a single component is scattered througout a theme’s stylesheets, reasoning about that component is difficult. When a single style rule may affect multiple components, making changes to a theme becomes dangerous. Keeping styles explicitly namespaced in separate files guards against this type of coupling.

  3. Maintainability. When each component has its own file, it’s easier to ensure that each component is properly namespaced; that is, its outer-most element has a class with the component’s name (atom-rule or organism-footer). When a component is properly namespaced, you can be more confident that all the code in that file only affects that one component, and that changes you make to that component’s styling won’t impact other components that haven’t explicitly used that component.

An Example

To demonstrate how styling for even simple components can become difficult to maintain over time, let’s look at an example. Say I’m building a theme, and I want all the headings from h1 to h6 to have a red line beneath them. I write the following styling in global.less:

h1, h2, h3, h4, h5, h6 { 
    border-bottom: 1px solid red; 
}

As I continue developing the theme, I decide I want hard rules to mirror the styling for headings, so I modify global.less like so:

h1, h2, h3, h4, h5, h6, hr { 
    border-bottom: 1px solid red; 
}

At this point I’ve already begun to couple two components, atom-heading and atom-rule we might call them, by using a CSS selector that targets both components. If later I want to change the color of the underline on headings but not on hard rules, I’ll first have to decouple the styling by breaking the selector block into two. This is a small example of the maintainability costs of this kind of coupling.

But it probably won’t end with the two components becoming coupled. As I continue developing my theme, since I’ve already started down the path of storing styling in global.less, more styling will probably accumulate there. And, at some point, I’m likely to decide that I want to make first-level headings bold, so I add this to the end of the stylesheet:

h1 { font-weight: bold; }

Now, not only is the styling for atom-heading and atom-rule coupled, but the styling for atom-heading is not in a single location. This fragmenting of the styling for a single component tends to lead to the accumulation of conflicting and complex styling, as developers making modifications to the theme in the future are not likely to be aware of all the different locations where styling exists to modify this single component.

File Structure

Each component has a name in the form of .layer-componentIdentifier. (For more information on naming components, see naming_things.md.) This name is used for a component’s Twig partial, Less file, and base CSS classname.

All component Twig partials are placed in the theme’s partial/ folder. All component Less files are placed in the theme’s style/ folder, and included at the end of global.less, grouped by layer and sorted alphabetically, within .su_bootstrap_safe if the theme uses Bootstrap.

// Variable declarations ...

.su_bootstrap_safe
  // Global CSS [minimize and eliminate if at all possible] ...

  @import "atom-button";
  @import "atom-search";

  @import "molecule-branding";
  @import "molecule-breadcrumbs";
  @import "molecule-carousel";
  @import "molecule-nav";
  @import "molecule-icons";

  @import "organism-footer";
  @import "organism-navBar";
}

Note that, even though each component Less file filename should end with .less, it’s not necessary to include the extension when importing the file in global.less.

Smells

“A code smell is a surface indication that usually corresponds to a deeper problem in the system” (Martin Fowler).

If you notice any of the following in a theme, it’s likely that the theme hasn’t been properly broken into components.