Atomic Design is a methodology outlining sensible code structure for stylesheets. It has a large following, but I find its naming conventions can sometimes be ambiguous. What’s a molecule? What’s an organism? How do we know where to draw the line between the two? These particular questions seem to be the greatest stumbling block for interpreting an atomic architecture.
Today we’ll discuss what I use, particular facets of atomic design’s conventions which I struggle with, what I’ve done to resolve my issues, and how I currently organize Sass using, for example, the 7-1 pattern.
Brad Frost, author of Atomic Design, has since clarified the fact that its methodologies don’t actually dictate any CSS structure. Instead, it offers a mental model for thinking about constructing user interfaces. Sorry Brad!
“We’re not designing pages, we’re designing systems of components.”—Stephen Hay
I love atomic design and its ideologies, but I’ve found they can collapse when working with team members who aren’t intimately familiar with how it all works. In the past I used the following folder structure:
- vars - functions - mixins - base - plugins - typography - atoms - molecules - organisms - templates - pages - states - utility style.scss
style.scss Sass partials are imported using gulp-sass-glob-import:
Sass Import Index File:
// Config @import "vars/*"; @import "functions/*"; @import "mixins/*"; // Bower Components @import "../bower_components/normalize-scss/_normalize"; // General DOM selector styles @import "base/*"; // Fonts & General Type Styling @import "typography/*"; // 3rd Party Addons @import "plugins/*"; // Atomic Design @import "atoms/**/*"; @import "molecules/**/*"; @import "organisms/**/*"; @import "templates/**/*"; @import "pages/**/*"; // Variations thru Events @import "states/*"; // General UI Helpers @import "utility/*";
The order with this setup matters quite a bit. If an “atom”, “molecule” or “organism” needs to be adjusted, declarations made in templates or pages will override the aforementioned parts, along with every other partial preceding.
The order additionally enables overrides to a plugin’s styling, should that need arise (and usually does in my experience).
Much of the contents for each atomic directory (atoms, molecules, organisms, templates, pages) will contain partials that are, in theory, easy to find and easily manageable when needed.
- atoms - _buttons.scss - _links.scss - _inputs.scss - molecules - _navigation.scss - _search-form.scss - _contact-form.scss - organisms - _header.scss - _footer.scss - _content.scss - templates - _sticky-footer.scss - _grid-2column.scss - _grid-3column.scss - pages - _home.scss - _about.scss - _contact.scss
The organization appears sensible if you’re wise to Atomic Design, but falls short for someone unfamiliar with the approach and nomenclature. A developer unaware of Atomic Design won’t make sense of the fact that a search form resides within the
molecules directory, and may set off searching in other areas to make edits, or simply get frustrated and make a new file; I’ve seen it happen.
A Components Structure
As of the time of this writing I take an approach envisioning elements entirely as components, like lego blocks, thereby creating an ease of use for all involved with the codebase. Take a look at the following directory structure:
- vars - functions - mixins - base - typography - plugins - toolbox - components - layout - pages - states - utility style.scss
Hopefully you can see by this example that it’s fairly intuitive to gather the purpose of each folder (with the exception of toolbox). “Toolbox” is a place to store helpers unrelated to utilities, such as custom classes for layout and object patterns, custom keyframe animations, and so on. These toolbox items, for me, usually end up as parts I may override or may want to in the future, and why they’re imported before the components directory.
At this stage partials are loaded into the styles index like so:
// Config @import "vars/**/**"; @import "functions/*"; @import "mixins/*"; // UI @import "../bower_components/normalize-scss/_normalize"; @import "base/*"; // general styling using DOM element selectors @import "typography/*"; @import "plugins/**/*"; // 3rd party add-ons @import "toolbox/**/*"; // Non-Utility Helpers @import "components/**/*"; // lego blocks @import "layout/**/*"; @import "pages/**/*"; @import "states/**/*"; @import "utility/**/*";
“Components” will contain pieces of the UI such as buttons, inputs, logos, avatars, header, footer, forms, and even modules such as navigation. Components can be anything, as long as they do one thing and one thing only, re-usable, re-used across the project and most importantly independent; not a bad definition to be universally understood if you ask me. This particular approach also implements various ideas from SMACSS (states) and Atomic Design (templates–called layout in this example–and pages).
In terms of way finding it’s much easier to locate the components directory and find the correlating interface part a developer may be tracking down; for example:
- components - _buttons.scss - _navigation.scss - _masthead.scss - _footer.scss - _logo.scss - _avatar.scss - _contact-form.scss - _sales-calculator.scss
Essentially, components is a one stop shop. Atomic design might work perfectly for a team of one, or even a team that is intimately familiar, but within a larger team setting the frustration can be felt.
Atomic Design can absolutely be used to keep minimal styling on elements in order to create meaningful and reusable interface components. But you may find certain aspects confusing. Decide for yourself what works best for you and draw conclusions from that. As with everything, this is just my experience and others may have a different stance.
I’d love to hear how you approach this scenario yourselves so let me know in the comments. Happy coding everyone!