---
tags: theming
---
# Theming with Variables - Web and Native
Just jotting down some ideas.
## Goals
What are the goals of adding CSS variables to the components?
## Limitations
Some limitations to impose on the system
- Only set at the theme / ThemeProvider level, in native this helps utilize what we are already setting in the provider since there is no equivalent to the actual variable functionality
## Consuming values
This is one where control tokens should be defined as references to variables. In essence we would write our constants as:
```ts
const ButtonDefaults = {
tokens: {
buttonBackgroundColor: var(buttonBackgroundColor)
buttonColor: var(buttonForegroundColor)
}
}
```
- `var()` is a function that can be set to transform into a CSS var reference or an implementation function
- This could be via babel transform or runtime, if runtime then native and IE 11 could share implementations
- Transform would happen at theme resolution time
## Setting / defining values
### Goals
- Keep it relatively simple
- Easy to consume
- Allow for additional power
### Potential Ideas
Starting with simplest and moving out from there
#### Theme.variables
Create a section in the theme called variables. This is equivalent in a lot of ways to semantic colors. The basic goal would be to have these be authorable by rules.
Something like:
```js
theme = {
colors: {
...color values
},
typography: {
...typography values
},
variables: {
shadedBackgroundColor: paletteRef('someBackground'),
shadedForegroundColor: contrasting(paletteRef('someForeground'), var('shadedBackgroundColor')),
// etc..
controlTextVariant: t => t.typography.variants.standard;
}
}
```
#### Theme.variableSets
This would allow a component to opt into a collection of variable values.
A "plate" set would be responsible for defining a collection of generalized colors that are accessible with each other.
```jsx
theme = {
color: {
accent: '',
accent100: '..',
accent900: '...'
},
variableSets: {
accentFill: {
backgroundColor: 'var(--colorAccent)',
backgroundColorHover: '...',
backgroundColorActive: '...',
backgroundColorPressed: '...',
backgroundColorDisabled: '...',
text: 'var(--colorNeutral500)',
textHover: '...',
textActive: '...',
textPressed: '...',
textDisabled: '...',
}
}
}
```
A component could then opt into the variable set as a class name to "apply" variable values in a specific scope:
```tsx
<ThemeProvider theme={...}>
<button className="accentFill ...">
</button>
</ThemeProvider>
```
__Rude Q & A:__
- What is the value of wrapping these in collections/classes? Do we think people will really use them as a set?
- Doesn't CSS have issues with application order amongst classes? How would you mix and match?
- Is this adding unnecessary complexity given all the knobs we have already?
- Are we really optimizing for runtime or design time here?
As an alternative how about:
1. Just make these flat and grouped accentBackgroundColor, accentBackgroundColorHover, etc.
2. If you want a control to reference those just change the tokens for the component to reference a different set
3. This allows mixing and matching if necessary, it also allows for creating relationships
#### Component variables
Potentially the biggest issue I see is that you want to keep definitions of things local to the components, but allow overriding at the theme level. We have this today in native with defaults for the components defined locally, but having them be overrideable via the theme. This allows for:
- theme definitions to remain light
- detailed settings to be defined in the components themselves
- those settings end up being pay for play, until a component is brought in you don't need it
The biggest question to me is how to enable this functionality for a variables based approach. The desired behavior would be (__assume variableSets above are componentVariables or something similar__)
##### 1. Defined in local component
Just make it flat for a component, they can create hierarchy with names
```
button: {
backgroundColor: var('--colorAccent'),
backgroundColorHover: var('...')
text: contrasting(var(''--colorNeutral500'), var('--backgroundColor'))
backgroundColorPrimary: whatever...
}
```
##### 2. Overridden in theme definition
```
theme = {
componentVars: {
button: {
// can just patch one
backgroundColor: 'blue'
}
}
}
```
Assuming a button token is authored as:
```
backgroundColor: var('button.backgroundColor')
```
The precedence should then go:
1. Use the theme variable value if specified
2. Use the local variable value if specified