How we used a ready-made design system as the basis of our design system, Pixel, but made it our own.
Supermetrics has been doubling in size for the past five years. In the beginning, the product was just a single sidebar within Google docs, and most code was on the backend. UI possibilities and requirements were limited. Today, Supermetrics has multiple applications and around ten front-end developers working across five teams. For the company, great UX is among the most critical competitive advantages.
The front-end applications have grown organically over the years. Because of the history, many UI components were not reusable. Styles were copy-pasted between applications. Despite SCSS variables and naming conventions, there were consistency issues with colors, spacing, and font sizes.
Building the new design system was one of my most exciting projects while I was working at Supermetrics. I had joined the company last October, and one part of my job description was "redesigning our Team site with our Head of Design." The main business drivers for the redesign were that development was slow, the UI was inconsistent, and it was hard to support the new most important user flows. Previously, the UI was mainly used for license and team management and was structured around those needs. Now, users have more complex needs like configuring and monitoring data transfers. This requires a very different approach to the UI.
Redesigning the Team site is a significant undertaking. It is Supermetrics' biggest custom UI written in React, TypeScript, and SCSS with hundreds of components and almost 100K lines of code. Redesigning it would also lead to updating the UIs of other applications to keep a consistent user experience across the product suite.
We started discussing with our Head of Design Ivana Pesic and some of the front-end developers what would be the best way for us to achieve our business goals: supporting the new flows, consistency across all our apps, and making development faster. One of the most promising ideas was to build a design system. This would allow us to have a central repository of UI components and assets together with accompanying guidelines and documentation.
Our team was already somewhat familiar with the concept of design systems but wanted to make sure it was a worthwhile undertaking. We read about other companies' experiences and resources like Brad Frost’s Atomic Design book to improve our understanding. These gave us further confidence that a design system could help us sustainably reach our goals.
We set out to create a design system of our own with four goals in mind:
Consistently great UI. Make sure all teams could create UIs that feel like they belong together.
Shared vocabulary. Improve the communication between designers, developers, and other stakeholders in the company around designing and building UIs with great UX.
Educating people within the organization. Raise the bar of our UI/UX design across the whole organization by giving people tools that help them.
Improve speed of development. Stop reinventing the wheel and copy-pasting when it is not useful.
Once we knew why we were building a design system, it was time to decide how we'd do it. Should we build our design system from scratch or use an off-the-shelf solution? Building from scratch gives you more control and makes the design system reflect your company brand better. However, it is very time-consuming, and there are no real guarantees that the result is any better than using an off-the-shelf one. To make a decision, we needed to know what we needed.
To gather design requirements, we:
- Did a component inventory of all the components we'd need.
- Refreshed our brand book and style guide.
- Made some designs to have an idea of the overall design style.
- Researched many of the available options to have a general idea of what ready-made solutions were available.
On the technical side, we listed out the technical things we'd want to have:
- Strictly-typed TypeScript. For great auto-complete and type-safety.
- Maintainable CSS. For us, this meant: style-colocation, avoiding global scope, dead code elimination, and enforcing the design system styles, while still allowing one-off overrides.
- Themeability. We knew we wanted to change the colors and fonts of any ready-made solution and themeability means that our changes are much less likely to break.
- Copy-pasteable component code. If we would need to modify some of the components heavily, we wanted to make sure we could use the original component as the basis.
With these requirements in mind, we researched if any of the ready-made options would fit. In this process, UXPin's Adele was very helpful. We found multiple promising options and dug a little deeper into them. At first, none of them seemed to fit our requirements, and we seriously considered building everything from scratch or using a UI component library like Chakra UI and adding the rest ourselves.
In the end, after much discussion and evaluation, we concluded Zendesk's Garden was the best fit for us in terms of technologies, default styles, and themeability. I sent the Garden documentation to some of our front-end developers for review, and all concluded that it looked good.
Although Zendesk's Garden matched our needs, we did not want just to copy their styles and call it a day. We gave the design system the name "Pixel" after our cute dog-mascot. We created a custom theme with our fonts, colors, shadows, and spacings. We also added some Supermetrics feel to the designs with small details like fully rounded buttons, SVG graphics, and hand-selected icons.
Also, on the technical side, we did not want our apps to depend directly on Zendesk's packages that we had no control over. We created a separate, privately hosted NPM package for Pixel, where we individually import and export the components that we want to use from Zendesk's packages. In this way, we can get all bug fixes and new features from Zendesk's Garden simply by updating our dependencies while still distributing our customizations to our own apps in a controlled way. We can also replace any part of the design system without affecting the consuming apps.
As we expected, there are pros and cons to using a ready-made design system.
Fast time to use. The design system was used in three apps in less than six months from the start of the project.
A great technical foundation. The design system we chose had a ready-made Storybook and tests that we can use even when making changes to the components.
More concrete discussion. Our design discussions often start with the capabilities of the design system we're building on top of. This frames the discussion, allows us to find practical solutions faster, and helps us iterate in smaller steps.
Unscheduled fundamental discussions. With a ready-made design system, you skip important fundamental discussions. Our organization thinks differently about design than Zendesk. The differences often manifest themselves when we're designing and building a feature. Sometimes we've needed to start unexpectedly asking very fundamental questions about things like buttons and links or animations.
Dirty overrides to the ready-made components. We've aligned our designs to the limits of the ready-made design system as much as is feasible. Still, we have needed style overrides for, e.g., button variants. These overrides always feel a little bit hacky and may break at some point when the ready-made design system breaks.
Accepting the trade-off we've made. We knew we were taking UI/UX and technical design debt when we chose to speed up things with a ready-made solution. This debt has to be paid back, and sometimes this happens at inconvenient times. Mentally accepting this and being prepared when working on new features helps.
Using a separate NPM package. We have mitigated most of the downsides of depending on an existing design system by our own private NPM Package. For example, we have already modified the Garden typography components heavily. We were able to copy-paste the original components to our package and modify them to our needs without making it feel hacky for consuming applications. We've also added a complete set of layout components inspired by SEEK's Braid design system, which we've built from scratch. For the consuming applications, there is no difference.
In total, Pixel is now used in four different applications. The redesign of the Team site with Pixel has also begun, which makes the team super excited. The redesign will require many new UI components, some of which will belong to the design system and some which are application-specific.
In its current state, Pixel is still more like a component library than a full-blown design system. The documentation around the thinking on design philosophy and copywriting guidelines still need to be polished. The work has only begun, but now there is a great place to iterate and improve on.