Pushing at the edges of themes in design systems

Originally published on Medium

As we mature in any niche, we find emergent language and different usage of familiar terms. How we talk about things also sets some constraints as we tentatively share mental models across our peer group. For me, themes fall into this category.

Some excellent articles have been written about theming within design systems, many of which demonstrate a theme as effectively a change of colour palette applied to the same components that might, for example, help express a different brand across your estate.

If you look over to the world of content management systems, the concept of a theme is essentially the whole front-end presentation of your site, using the same content from the system in whatever way you’d want (like this example for Wordpress).

Between these uses of the same term, we have much to explore when it comes to design systems. If we assume that we use some form of design tokens or a similar way of storing design decisions, it opens us up to a huge raft of possible changes. With this in mind, I often think of themes in a design system as an application of brand but that still doesn’t feel adequate. If we have the scope of changing more visual properties from typography and colours but also dimensions and even how we describe movement, the capacity to make significant changes opens up.

An example button with different themes applied to a button, changing colours or radius and padding

Given what we can store as design tokens, this is all quite foundational stuff. The base design decisions we capture. When we look at more elaborate opportunities with themes (alluding to the CMS example), there’s the potential for us to get to a point where we need to describe an implementation detail. At this point that feels beyond the scope of a design system, certainly in terms of what we can store in tokens, but we could come across these things in relatively trivial ways.

Perhaps your design system powers a native app (for iOS and Android) aimed at phones and you also have a responsive website. If you look at a button on its own, abstracted in the design system, it may look similar if not exactly the same. Their context of use may differ. Let’s assume we have this button used within a card component. On native platforms, we opt to have that button fill the width of the card but on the web, we choose to let the text within the button define its size (as it’s a more variable space). This is a detail that could be captured within the card component as its implementation would be through different codebases. In this way, our theme now has a shared responsibility between what’s encoded in tokens and what is done at the time of implementation.

Showing the same button full width or responding to the width of its text

Expanding our example, what if we have a second brand that should make use of all the components we’ve already created? This brand has a different personality and may want to do something a little different to talk to that brand’s audience in the right way. Beyond just changing colours, they’d like to bring in a more playful aesthetic. The button is positioned over the edge of the card and rotated a little — y’know, jaunty and fun-looking.

The left example shows the same button within a card, aligned to the bottom left, while the one on the right shows it recoloured, more rounded, positioned across the edge of the card, rotated and has a shadow

It’s the same button component, in the same card component but the scope of what we’ve done in a theme has been pushed a little further. The positioning and rotation of the button within that context changes. Do we leave that as an implementation detail that a developer can implement however makes sense to them or do we see a need for our design system or even tokens to store a greater depth of these decisions?

In the code, across themes, across components might end up with simple logic swapping out chunks of CSS for the web but also how we describe styling in iOS and Android, so the extent of our theme now has these tentative chunks of conditional logic linked to the switch in tokens, across our codebases. At first, this might feel manageable but everything we create is tomorrow’s legacy, so maintaining and keeping it flexible is a real concern.

Where this line of thinking takes me is that admittedly, not everyone needs themes at all. Your site or app might have a single look and feel and that’s all it’d ever need. You might be content with creating a dark mode theme (arguably can be more than just a simple switch of colour palette), so what I’m describing here is exploring edge cases. My take would be to treat your current look and feel as a default theme to allow you to evolve more easily in future.

For a large organisation, having really robust components that can keep evolving as the people within the org learn more and find new use cases, having a collection of white-labelled components might be the right approach. It’s here where pushing at the edges of what the design system community currently means as a theme is a curious thing. What is something the system should control and what is an implementation detail? If we have a volume of implementation details, how can or should we describe a way to capture and illustrate them to help with ongoing maintainability?

A button might just be a button and the source of so many design system blog posts. It’s what you do with the button, its contexts of use and the different ways you might want to use it that can make it a useful gateway into a topic like this. Amplify some of these concepts beyond the button, across the whole of your components library and it becomes an interesting experiment. How far is too far with themes?