We embarked on a journey to create a design system at FreeAgent over 2 years ago. In this blog post I will describe how we structure our design system code and how it’s being used across different codebases.
Technologies we use
We ship our design system code in a few packages:
- A Ruby gem for the Ruby components
- 2 npm packages:
- a design tokens package which contains our visual design atoms as key-value pairs, across a range of technology formats
Ruby components gem
The Ruby gem is structured as a Rails engine which is seamlessly integrated into the main FreeAgent Rails application, as well as the Lookbook Rails application.
To ensure code consistency and quality, we adhere to the official FreeAgent Ruby style guide, and we use Rubocop to lint our code.
We use the ViewComponent framework as it provides conveniences for building cohesive components that are also easy to test in isolation. Our components are purely presentational, with no reliance on business logic which makes them highly reusable.
We use slots frequently as it helps us separate concerns in our components.
For testing, we write Rspec unit tests for each component. An improvement we would like to make in the future is to write tests directly for our component previews.
UI npm package
We structure our CSS using SCSS files for each component, as well as utilities. The SCSS files from this package are then imported into the FreeAgent SCSS files and all built together.
To ensure code quality, we use eslint and stylelint which we run in our CI on each build. We test our Stimulus controllers using Jest.
The consumers for this package are the FreeAgent web application and our Design System documentation website.
Design tokens npm package
According to the W3C Design Tokens Community Group, design tokens are “stylistic pieces of a design system”, such as colours or spacing.
At the moment, this package is only being used in our documentation website because we are in the process of overhauling the way we build and package design tokens so that we can export them straight from our design tool, Figma. This will allow us to have a centralised place where design tokens are defined, and put the control over colours and spacing into the hands of our design team.
The design system consumers
The FreeAgent application
Our main design system consumer is the FreeAgent web application. It uses both the Ruby gem and the UI npm package.
While the Ruby gem is included as an engine and requires no further configuration to “just work”, the UI npm package SASS files are included in the main application one and built together. In the future, we might look at serving up the Design system as a minified file and remove the dependency of building it in the application.
We use Lookbook to view and test our components in isolation, without needing to have an instance of the main application running. During the build process of a component, Lookbook enables us to have a prototype running quickly which helps in discussions with our design colleagues.
We build previews for each component and use the parameters panel to be able to view different variations in one place.
We have a documentation website for our design system which is aimed at designers and engineers working with FreeStyle. This is our design system storefront.
The documentation website uses both the UI npm package as well as the design tokens package. We need the styles and variables from both to accurately display examples of our components.
We version our packages using semantic versioning. We release all packages at once when at least one is updated. This simplifies the release process as there’s just one version to think about across all packages.
Our release process is automated via Github actions which build and release our packages on demand.
We are planning to evolve our design tokens, both from a naming and organisational perspective, so that we can distribute them across all of our products, including multiple websites and our native apps.
At the moment, our components are written in a Rails specific framework. However, in the future we would like to look into creating technology-agnostic versions of our components using web components. This would help with reach, as we could consume them in any web application, for example our marketing website as well.