A theme is the static configuration of a theme-able system. This requires a way to express the configuration and a theme-able system that is responsible for using the configuration to apply the expected styling.
I would argue that a good theme system has two key properties:
The interface consists of high level semantic variables that can be reused. This is where you assign values to variables such as primary
, accent
, etc. This is a convenient abstraction over specific assignments of values to style properties. It makes it easy to quickly customize a system with a different set of tokens.
At some point you need to decide what a style property should be. Assignment is the baseline for a theme. If we consider a theme to be a "static configuration of a theme-able system", the set of our assignments is equivalent to the theme itself.
// button source code
<button style={{backgroundColor: '#000'}} />
Ideally we can use semantic variables from our theme interface.
// theme config
const $theme = {
primary: '#000',
};
// button source code
<button style={{backgroundColor: $theme.primary}} />;
In this approach, you have hard-coded a single mapping of semantic variables to assignments. That is, button
will always use the primary
variable. But what if someone wants to use an alternate mapping? Let's say they want to use their accent
variable for the button background?
// theme config
const $theme = {
primary: '#000',
accent: '#00F',
};
const $map = {
buttonBackgroundColor: $theme.primary,
};
// button source code
<button style={{backgroundColor: $map.buttonBackgroundColor}} />;
Here we are introducing an intermediary layer for mapping semantic theme variables to the actual style property assignment. This allows us to create alternate theme mappings:
// this project wants to use the accent color for buttons
const $map = {
buttonBackgroundColor: $theme.accent,
};
This makes our theme system more flexible but brings up an important question: Should we allow for alternate mappings in our theme system? If we are okay with having one mapping hard-coded than we don't require this layer of configuration.