Front-end rules to live by

There’s a lot that goes into creating a Design System. Front-end code has traditionally been easy to bloat and hard to maintain over time. Eventually, you just tear it all down and start again.

Gav McKenzie
Gav McKenzie
How-to, Industry, Engineering

In this article

There’s a lot that goes into creating a Design System. Front-end code has traditionally been easy to bloat and hard to maintain over time. Eventually, you just tear it all down and start again.

We’ve been working on component libraries and Design Systems for a while now. Some of our front-end UI libraries started life over 5 years ago and are still going strong – having been through multiple tech stacks.

In this article, we’ll be looking at some basic principles you can follow to help keep your code organised and maintainable for years to come.

Group files by component

A fundamental rule of programming is the separation of concerns. Until recently, for front-end developers, this meant separating files by type of code: HTML, CSS, JavaScript, Assets.

Your folder structure might looks something like this.

/src
/scss
_alert.scss
_input.scss
_typography.scss
main.css
/js
alert.js
input.js
/templates
alert.hbs
input.hbs

This setup treats the templates, CSS and JS as separate entities that do not care about each other. However, we can infer from the naming pattern that the files _alert.scss, alert.js and alert.hbs are intrinsically linked.

Rather than grouping by file type, files should be grouped by component. But what about separation of concerns?! The component itself is not concerned with the code in the rest of the app, it just provides an interface to be interacted with.

/src
/components
/alert
_alert.scss
alert.js
alert.hbs
/input
input.scss
input.hbs

Keep a single source of truth

The component folder should contain all programmatic references to the internals of the component. Any time component internals are referenced in another folder it creates unexpected side effects and maintenance holes.

// _home.scss
.home-page .alert {
background: blue;
}

In the example above, alerts on the home page are given a blue background. If we were to re-style alerts, there would be no way of knowing about this variation and it could easily be missed. Even if not missed, all special instances would need tracking down and correcting, potentially adding hours of work.

The better solution would be to update the alert interface within the alert folder to handle the variation, keeping all the code neatly contained in a single folder.

// _alert.scss
.alert--info {
background: blue;
}

This also applies in the templates. Internal component HTML classes should never be referenced outside of the component folder.

<!-- home.html -->
<alert>
<div class="alert__inner">
Some content
</div>
</alert>

In the example above, an inner component class has been referenced from the home page. If child components are needed, they should be created within the component folder and ideally exported as part of the component module. Again, this keeps all variations and related subcomponents in a single location for visibility during maintenance or refactoring.

<!-- home.html -->
<alert>
<alert-inner>
Some content
</alert-inner>
</alert>

Stick to one component

Each component folder should only contain a single component. If you were using BEM, this would be the “block” part of the naming structure. Components can be grouped into folders, such as form controls, but each component itself should be an isolated example.

This helps to keep each folder solely focused on a single piece of functionality, without the code becoming diffuse.

/components/
/controls
/input
input.js
input.scss
input.hbs
/select
select.js
select.scss
select.hbs

Folders === components === classes

Each folder should have the same name as the component within, which should in turn have the same class names. As well as reducing the chances of class name duplication (if you are not using scoped CSS), this helps to make components easier to find.

When inspecting a component in the browser, you should be able to instantly tell which file the code comes from by looking at the class name.

Assuming the previous rules have been followed, this will point to the single folder that contains all the code for this component, speeding up any debugging.

/MyAwesomeComponent
MyAwesomeComponent.hbs ## contains .my-awesome-component

Keep documentation close to the code

Stale or incorrect documentation is as bad as no documentation. One of the problems we often see is documentation being separated from the components. Whether in a separate folder or on a separate platform, it rapidly becomes out of sync with the reality that is the code.

Documentation should be stored in the same folder as the component it is documenting, in order to make it as easy as possible to keep it up to date. The documentation should include live examples mixed in with the text, so other developers don’t need to flip back and forth between the text and the reality.

Documentation for a button with different size variants

Make it easy to delete

Now we have all the code for a component (including the documentation) in a single folder, this rule becomes almost automatic. Components age and sometimes they need to be retired or refactored. By having the code in a single folder, we can simply delete the folder and know that all the code for that component has been removed.

There may still be instances of the component in use which will need to be tidied up, but these are much more reliably removed than programmatic references that can be left dangling for years.

Parents set boundaries, children grow to fit them

A common reason for code “leaking” out of its component folder and into other files is the need to tweak the layout for a component. A margin here, some padding there...

Components should not be moved around directly, just given a layout slot to fill. The size and position of the slot can be controlled, but anything within the slot should be free to expand to fill the space, being in control of its own display properties.

This keeps slots as generic as possible and prevents overly specific layout styling for child elements, making both parent and child components more reusable.

Use the design tokens

Design tokens are the smallest building blocks of your CSS framework. They are a set of variables that control things such as palette, fonts and spacing which can be used throughout the rest of the project.

When writing the CSS for a component, there should be no “magic numbers”. Where possible all values should be taken from the design tokens. This helps to keep values consistent across components and gives the overall system a unified feel where everything lines up and fits together well.

There’s an example of a set of design tokens we might use up on the Etch Github.

Enforce accessibility

We all want to write websites that as many people can use as possible. However, it’s easy to miss things that you can’t always see. Much like you probably (and should!) use a JavaScript linter and hopefully a SASS linter (or similar), you should be linting for accessibility.

An accessibility linter will catch problems in the code before it even gets into a browser, such as missed for attributes or missing keyboard events.

Accessible code doesn’t just benefit users with disabilities. Different people use computers in different ways and an accessible website is a well-written one that is robust and easy to consume with different input/output methods.

Here’s a couple of our favourite a11y linters:

Never say “just this once”

With all these rules it’s easy to say “I need to break the rules just this once” and throw in a hack to finish up the work you are doing and get out. Once you've broken the rules once, it turns into 10 times, then 100, then... you're back to reading articles on how to organise your front-end code.

By forcing discipline in each and every component, the overall speed of development increases as maintenance and bug fixing costs diminish. What seems like a large initial investment pays off many times over in the coming months. Stay strong!

Etch is a web software consultancy based in the UK©2012-2024 Etch Software Ltd - Policies