Creating Scalable UIs: Theming & Configuration

How to Boost Your Productivity When Using React

Edmund Reed
Valtech Design
10 min readAug 11, 2019

--

When it comes to UIs, theming and configuration are both concerns that warrant being separated. This means that their nature should not depend too much on the host framework (e.g React). Ideally, I should be able to hook some existing theme or configuration into multiple projects that use different frameworks. The whole point of separating concerns is to increase scalability and portability (and hence, maintainability), so by treating our theming and configuration as separate concerns, we can do just that.

In modern UIs, you often have libraries of UI components. Themes can be thought of as the configuration for the UI as a whole, whilst your individual UI components can also have their own configuration. In this article, I’ll explore how to make the most out of theming and UI configuration when using React (though a lot of the explored ideas would apply across-the-board, regardless of the technologies you use).

Themes

The goal of a theme might be:

  • share/reuse certain properties
  • provide tools/utilities
  • branded microsites
  • apply cosmetic updates

Depending on your setup/goals (and whether you are even using themes), you may have just one theme, or you may have multiple themes. You may even have a foundation theme on which subsequent themes are based, preventing the need to duplicate properties that may not change between themes (for example, your theme may contain responsive breakpoint values, but these may be constant between your themes, so duplicating them would be a poor Developer-Experience).

Provide/Expose a Theme

After looking at the potential goals of a theme, it’s worth considering how a theme might be used. Given that our UI is a collection of components, we would perhaps naturally want to expose our theme(s) to our components. Now, at this point, the method of providing and consuming a theme may very well depend upon whatever framework you’re using, but if we were using React, I can see three ways to provide/expose a theme to some components:

  1. import manually into each component
  2. attach to window.theme (or something)
  3. create a <Provider> component

The first two methods could perhaps apply to any framework, but I’ve typically seen the third method used in other projects that use React and themes, which is to use a Provider component, utilising React’s context under the hood. But really, it doesn’t matter so much how a theme is exposed to your components, so long as it is.

Consume a Theme

Once your theme is exposed to your components, the next consideration is how it will be utilised. Predominantly, one might assume that a theme relates to look and feel, which in the context of a UI component means styling (or presentation). Though, it’s not out of the question that one may require theming values for rendering logic as well. If we’re wanting to share our themes across concerns (i.e ensuring the theme is exposed to both styling and rendering aspects), for the sake of argument, we will assume that we are using React to render our components. We will also assume we will use some CSS-in-JS solution to handle styling (using the same technology, i.e JavaScript, makes it easer to share values between concerns). Of course, your setup could quite easily, and efficiently, rely on Sass themes alone, if your rendering logic didn’t depend upon your themes.

Let’s look at an example of how a theme might be provided and consumed by a UI component. Firstly, we need a way to provide/expose it:

This would be the <Provider> component to which we pass our theme. It would be used like so:

Access Theme Within JSX

To access the theme within your component’s JSX (i.e MyComponent.jsx), you could now do (if using functional components + hooks):

Your theme is now available to your UI component. Assuming you are using a competent CSS-in-JS solution, you should be able to incorporate the theme into your styles. If we need any theme values to control our component rendering, at this point it would be no different to using props to control the rendering.

My only issue now is that if I want to use my theme in any component, I must manually import the context into it. If my project only had a single theme, this wouldn’t be much better than merely manually importing the theme in each component. We can fix this by creating a Higher-Order-Component or by using render props. Either way, we would need some sort of new wrapper component, and I’m personally a fan of the render props method (probably because I’ve only recently understood what they are).

To get from the previous example to this, we have:

  • Swapped the div wrapper element with a custom Component element
  • …allowing us to pass a render prop
  • …allowing us to access our theme
  • Removed the useContext hook

The current example could also be re-written as:

…which seems to be basically the same thing, except without using a render prop (our custom Component element would handle the logic to execute the function either way).

Introducing a custom Component element simply for this purpose alone would probably be overkill (if you have to import Component into every UI component to get the theme, why not just import the theme or theme context directly?). However, having such a custom component will allow us to also provide styling and configuration to the component, and potentially other things down the line (essentially any shared logic between UI components). It’s important to note that this hypothetical Component would still render an element to the DOM, so does not add any clutter to your JSX — we are simply replacing whatever the wrapping HTML element would be for your UI component with a more useful element.

Since we acknowledged that UIs are a collection of components, and we’re using React, it actually makes sense to have some sort of custom Component to use instead of divs, at least for the wrapping element of our components. For example, if we were using just divs, we would have no control over the props passed to them, and wouldn’t be able to render anything from them.

UI Components

Within the context of individual UI components, it’s more likely we will want to use our theme for styling purposes than for rendering purposes. Without there being a standard way to style React components currently, and with existing solutions offering radically different APIs/experiences, it makes it difficult to talk about abstract (but still general) concepts like relating theming to styling. To me, we should be in a state where we have UIs that are built from components, where each component can be fed a styles object (or fed some sort of stylesheet; 1 stylesheet per component). Many productive workflows currently offer this luxury, but given the disruptive nature of React we now have unusual concepts like Styled Components, stirring the pot.

For the sake of argument I’m going to pretend I’ve just discovered React, I have an existing theme and configuration for a component, and I want to now create a stylesheet for my component which utilises my theme. I will start with some pseudo code to act as the API and worry about the implementation later (i’d rather not let the limitations of existing tools/technologies dictate how I do something). The only assumption I will make is that I’ll be using CSS-in-JS instead of Sass (or rather, using JavaScript for styling instead of CSS).

Consume a Theme

So I now want to create a JavaScript stylesheet for my UI component, which utilises my theme. This is enough information to draft up an API. When consuming the theme within the module’s JSX, we used a function that accepted a theme parameter. Consistency is king, so it’s the same story here:

The above code uses plain JavaScript objects to handle CSS properties and values, but another popular convention when it comes to CSS-in-JS is to write CSS syntax inside Tagged Template Literals (TTLs) (read more about Objects vs TTLs for CSS-in-JS):

Without any specific solution in mind, this would be my ideal basis for having a theme in React and exposing it to my component’s styles. Given the JSX we have from previous examples, the natural way to go might be something like:

Using an existing solution such as React-JSS, without using a wrapper Component, might leave you with something like:

…requiring you to handle certain things manually. When it comes to UI components within your project, without having some sort of HOC there will likely be certain things you end up repeating (use as the useContext and useStyles calls), which is why having a HOC (<Component> in this case) to use instead of a div to handle all this repetition can be really useful.

Component Configuration

So far we’ve looked at how to provide a theme to your UI components and consume it within the styling and rendering realms (with the styling realm being the more useful/common realm). We acknowledged that a theme acts as the UI’s configuration, and that each individual UI component can have its own configuration. The configuration for a UI component should have access to the project’s theme (the UI’s configuration) and should also be exposed to its corresponding styles.

When you create UI components for projects at scale, it’s likely that you will want some of its aspects to be configurable. Configuration could relate to look and feel, functionality, accessibility, performance, literally any concerns that apply to UIs. It’s also unlikely that any component would become so large as to require multiple configurations (e.g a look-and-feel configuration, a functionality configuration etc.) — even at scale, all configuration pertaining to an individual UI component should be able to exist comfortably in a single object.

Keeping in-line with the other pseudo APIs whipped up in this article, to expose our project’s theme to our component’s configuration we will create a function that accepts a theme argument:

Now we’re in a position to utilise these values within our component’s styles, so we can pass a config argument alongside our theme:

(Notice how we are passing the arguments to a destructured object — we don’t do this in the configuration because for this guide we only ever need to supply a single theme argument) Using our trusty <Component> utility, our JSX could now exist as:

Just to take a reality check for a moment, without using the <Component> HOC, at this point our JSX would resemble:

Access Config Within JSX

Earlier we looked at how to access a theme within your component’s JSX using render props as a potential solution. As our configuration exists as a function, we would need to access its evaluated values, so cannot simply pass the reference we import (in the previous example, useStyles is a hypothetical hook that evaluates the configuration). When using our <Component> HOC, we could stick with using a useStyles hook, or we could use render props. Modifying the previous example to pass config alongside theme would leave us with:

The config argument in the render function will now be the evaluated configuration. It’s more likely you would want to access your component’s configuration within its JSX than its theme, as configuration doesn’t just pertain to the look and feel. If any part of your render logic was prone to changing, you could easily have it as part of the component’s configuration.

<Component>

Again, this is all theoretical pseudo code, but our <Component> HOC would look something like:

Top-tip: Make React and Component available globally

I realise many people are against “polluting” the global scope with anything, but when it comes to creating UI components in the fashion outlined by this article, constantly importing react and Component in every file becomes very tedious, and feels WET. I personally like to try and keep the source code for my components as clean as possible. Adding references that are imported inside every file to the global scope, and refactoring the MyComponent example to utilise React’s defaultProps leaves my source code as:

Removing all the fluff keeps the component’s source code clean and concise, whilst also offering the potential for CSS-in-JS, configuration, and theming possibilities without tightly coupling the existence of a theme (which may or may not exist).

Conclusion

In this article we’ve looked at how to create UI components using React whilst hooking existing themes and configuration into them to facilitate things like styling and rendering, from both theoretical and technical/practical perspectives, and ended up with APIs that follow a good separation of concerns. The most impactful aspect discussed has been the creation of a HOC (i.e <Component>) to handle rendering elements to the DOM instead of using raw HTML elements like divs. This HOC largely acts as a gatekeeper allowing you to map the pseudo-APIs outlined in this article to a real solution. The pseudo-APIs could probably be adjusted to work with existing solutions (such as React-JSS) without too much trouble.

If you’re interested in following my progress on creating a solution that is compatible with the APIs discussed in this article, checkout the project Lucid:

View Lucid on Github

Lucid’s goal is to offer no nonsense JavaScript styling for React DOM projects, and is essentially a collection of HOCs similar to <Component> used in this article.

Further Thoughts

Some relevant concepts that are perhaps a bit too in-depth for this article include:

--

--

Edmund Reed
Valtech Design

Design Systems Architect 🎨 UI•UX designer & developer 💻 I take front-end thought experiments too far 🧪 @valtech 💙