Skip to content

Commit 5f12cf0

Browse files
committed
docs(emotion,ui-themes): better documentation for theme overrides
More examples, document edge cases
1 parent ce86cdb commit 5f12cf0

File tree

3 files changed

+244
-67
lines changed

3 files changed

+244
-67
lines changed

docs/guides/using-theme-overrides.md

Lines changed: 230 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ order: 2
99
This document gives an overview on how you can customize Instructure UI components by tweaking their theme variables.
1010
While this gives you a level of flexibility on the look and feel of the components you should be aware of 2 things:
1111

12-
- The default theme variables are tested to have high enough contrast ratios for WCAG 2.1 conformance. If you are making changes, please make sure that your app stays WCAG conformant.
12+
- The default theme variables are tested to have high enough contrast ratios for WCAG 2.1 AA conformance. If you are making changes, please make sure that your app stays WCAG conformant.
1313
- The look of components is only customisable to a certain degree. This is intentional, because Instructure UI is a design system geared towards the Canvas "look and feel", not a generic UI component library.
1414

1515
```js
@@ -25,63 +25,32 @@ type: embed
2525
</ToggleBlockquote>
2626
```
2727

28-
### How theming works in InstUI
28+
### Using a different theme for a DOM subtree
2929

30-
The theming system in InstUI has these levels:
31-
32-
**The application level theme**
33-
34-
On the broader level, there is the main theme object that contains the color, spacing, typography etc. variables available in the theme (e.g.: [canvas theme](/#canvas)). The application level theme can be set via the [InstUISettingsProvider](/#InstUISettingsProvider) component.
30+
By nesting the `InstUISettingsProvider` you can apply different themes to some sections of you app.
3531

36-
```jsx
32+
```js
3733
---
38-
type: code
34+
type: example
3935
---
40-
// app/component root sets the app theme
4136
<InstUISettingsProvider theme={canvas}>
42-
<ExampleComponent />
43-
</InstUISettingsProvider>
44-
```
45-
46-
**The component's own theme**
47-
48-
Every themeable component has its own "theme map". This map defines the components own theme variables (used by this component only), and maps them to values in the global theme object. These local variables are then passed to the component and used in the styles object.
49-
50-
See the [emotion](/#emotion), [built-in themes](/#ui-themes) and [InstUISettingsProvider](/#InstUISettingsProvider) docs pages for more info and examples.
51-
52-
Either you set up the themes globally, or you use the `InstUISettingsProvider` to set up themes, the component's `theme.js` will map it to theme variables:
53-
54-
```jsx
55-
---
56-
type: code
57-
---
58-
// component's `theme.js` maps the
59-
const generateComponentTheme = (theme) => {
60-
const { colors } = theme // global theme, e.g.: canvas theme
61-
62-
return {
63-
background: colors?.UI?.surfaceDark,
64-
color: colors?.UI?.textSuccess
65-
//...
66-
}
67-
}
37+
<div>
38+
<Alert variant="info" margin="small">
39+
I am a "canvas" style Alert.
40+
</Alert>
6841

69-
// component's `style.js` uses the theme variables
70-
const generateStyle = (componentTheme) => {
71-
return {
72-
button: {
73-
label: 'button',
74-
background: componentTheme.background,
75-
color: componentTheme.color
76-
//...
77-
}
78-
}
79-
}
42+
<InstUISettingsProvider theme={canvasHighContrast}>
43+
<Alert variant="info" margin="small">
44+
I am a "canvasHighContrast" style Alert.
45+
</Alert>
46+
</InstUISettingsProvider>
47+
</div>
48+
</InstUISettingsProvider>
8049
```
8150

82-
### Application level theme overrides
51+
### Overriding parts of a theme
8352

84-
`<InstUISettingsProvider/>` accepts full theme objects and override objects too.
53+
You can modify parts of a theme object:
8554

8655
```js
8756
---
@@ -101,9 +70,45 @@ type: example
10170
</InstUISettingsProvider>
10271
```
10372

104-
#### Full themes
73+
Or modify a theme inside a subtree in 2 ways:
10574

106-
By nesting the `InstUISettingsProvider` you can apply different themes to some sections of you app.
75+
```js
76+
---
77+
type: example
78+
---
79+
<InstUISettingsProvider theme={canvas}>
80+
<div>
81+
<Heading level="h3" margin="small small medium">
82+
I should have default font family.
83+
</Heading>
84+
85+
<InstUISettingsProvider
86+
theme={{ typography: { fontFamily: 'monospace' } }}
87+
>
88+
<Heading level="h3" margin="small small">
89+
monospace font family set via override on the parent theme.
90+
</Heading>
91+
</InstUISettingsProvider>
92+
<InstUISettingsProvider
93+
theme={{
94+
themeOverrides: {
95+
canvas: { typography: { fontFamily: 'monospace' } }
96+
}
97+
}}
98+
>
99+
<Heading level="h3" margin="small small">
100+
monospace font family set via override only if the parent theme is 'canvas'.
101+
</Heading>
102+
</InstUISettingsProvider>
103+
</div>
104+
</InstUISettingsProvider>
105+
```
106+
107+
### Overriding theme for a specific component in a subtree
108+
109+
You can override the theme variables of specific components too with the `componentOverrides` key. You can do this for every theme or for just a given theme.
110+
111+
**Important:** these variables are the components own theme variables set in the `theme.js` of the component.
107112

108113
```js
109114
---
@@ -112,43 +117,203 @@ type: example
112117
<InstUISettingsProvider theme={canvas}>
113118
<div>
114119
<Alert variant="info" margin="small">
115-
I am a "canvas" style Alert.
120+
I am a default style Alert.
116121
</Alert>
117122

118-
<InstUISettingsProvider theme={canvasHighContrast}>
123+
<InstUISettingsProvider
124+
theme={{
125+
componentOverrides: {
126+
Alert: {
127+
infoIconBackground: "darkblue",
128+
infoBorderColor: "darkblue"
129+
}
130+
}
131+
}}
132+
>
119133
<Alert variant="info" margin="small">
120-
I am a "canvasHighContrast" style Alert.
134+
My icon background and border should be dark blue in any theme.
135+
</Alert>
136+
</InstUISettingsProvider>
137+
138+
<InstUISettingsProvider
139+
theme={{
140+
themeOverrides: {
141+
canvas: {
142+
componentOverrides: {
143+
Alert: {
144+
warningIconBackground: "deeppink",
145+
warningBorderColor: "deeppink"
146+
}
147+
}
148+
}
149+
}
150+
}}
151+
>
152+
<Alert variant="warning" margin="small">
153+
My border and icon background should be deep pink just if the 'canvas' theme is active.
121154
</Alert>
122155
</InstUISettingsProvider>
123156
</div>
124157
</InstUISettingsProvider>
125158
```
126159

127-
#### Partial theme overrides
160+
For child components both the displayName (`'InlineList.Item'`) and the componentId (`List.Item.componentId`) can be used as keys in `componentOverrides`.
128161

129-
When providing a partial theme object, you can override any theme variable inside that provider.
162+
```jsx
163+
---
164+
type: code
165+
---
166+
<InstUISettingsProvider
167+
theme={{
168+
componentOverrides: {
169+
'InlineList.Item': {
170+
color: 'blue'
171+
},
172+
[List.Item.componentId]: {
173+
color: 'red'
174+
}
175+
}
176+
}}
177+
>
178+
{/* ... */}
179+
</InstUISettingsProvider>
180+
```
181+
182+
### Overriding theme for a single component
183+
184+
Themeable components (that implement the [withStyle](#withStyle) decorator) accept a `themeOverride` prop. This prop let's you override the component's own theme. It accepts an object or a function.
185+
186+
The available theme variables are always displayed at the bottom of the component's page (e.g.: [Button component theme variables](/#Button/#ButtonTheme)).
187+
188+
#### Override object
130189

131190
```js
132191
---
133192
type: example
134193
---
135-
<InstUISettingsProvider theme={canvas}>
194+
<div>
136195
<div>
137-
<Heading level="h3" margin="small small medium">
138-
I should have default font family.
139-
</Heading>
196+
<Button color='primary'>Default Primary Button</Button>
197+
</div>
140198

199+
<div>
200+
<Button color='primary'
201+
themeOverride={{ primaryBackground: "purple" }}
202+
margin="small 0 large">
203+
Purple Primary Button
204+
</Button>
141205
<InstUISettingsProvider
142206
theme={{
143-
typography: { fontFamily: 'monospace' }
207+
componentOverrides: {
208+
TextInput: { background: "yellow" }
209+
}
144210
}}
145211
>
146-
<Heading level="h3" margin="small small">
147-
I should have monospace font family.
148-
</Heading>
212+
<DateInput2
213+
renderLabel="This is how to handle override in a nested component"
214+
screenReaderLabels={{
215+
calendarIcon: 'Calendar',
216+
nextMonthButton: 'Next month',
217+
prevMonthButton: 'Previous month'
218+
}}
219+
width="20rem"
220+
invalidDateErrorMessage="Invalid date"
221+
/>
149222
</InstUISettingsProvider>
150223
</div>
151-
</InstUISettingsProvider>
224+
</div>
225+
```
226+
227+
#### Override function
228+
229+
The override function's first parameter is the component's own theme object, the second is the main theme object.
230+
231+
```js
232+
---
233+
type: example
234+
---
235+
<div>
236+
<div>
237+
<Button color='primary'>Default Primary Button</Button>
238+
</div>
239+
240+
<div>
241+
<Button
242+
color='primary'
243+
margin="small 0 0"
244+
themeOverride={(componentTheme) => ({
245+
primaryBackground: componentTheme.successBackground,
246+
primaryBorderColor: componentTheme.successBorderColor
247+
})}
248+
>
249+
Default Primary Button with Success colors
250+
</Button>
251+
</div>
252+
</div>
253+
```
254+
255+
You can access and use any global theme variable via the second parameter (e.g. the [canvas theme](/#canvas)). When changing themes, these variables will update too.
256+
257+
```js
258+
---
259+
type: example
260+
---
261+
<div>
262+
<div>
263+
<Button color='primary'>Default Primary Button</Button>
264+
</div>
265+
266+
<div>
267+
<Button
268+
color='primary'
269+
margin="small 0 0"
270+
themeOverride={(_componentTheme, currentTheme) => ({
271+
primaryBackground: currentTheme.colors.primitives.orange57,
272+
primaryBorderColor: currentTheme.colors.primitives.green45,
273+
borderWidth: currentTheme.borders.widthLarge,
274+
borderStyle: 'dashed'
275+
})}
276+
>
277+
Custom Primary Button
278+
</Button>
279+
</div>
280+
</div>
281+
```
282+
283+
**The component's own theme**
284+
285+
Every themeable component has its own "theme map". This map defines the components own theme variables (used by this component only), and maps them to values in the global theme object. These local variables are then passed to the component and used in the styles object.
286+
287+
See the [emotion](/#emotion), [built-in themes](/#ui-themes) and [InstUISettingsProvider](/#InstUISettingsProvider) docs pages for more info and examples.
288+
289+
Either you set up the themes globally, or you use the `InstUISettingsProvider` to set up themes, the component's `theme.js` will map it to theme variables:
290+
291+
```jsx
292+
---
293+
type: code
294+
---
295+
// component's `theme.js` maps the
296+
const generateComponentTheme = (theme) => {
297+
const { colors } = theme // global theme, e.g.: canvas theme
298+
299+
return {
300+
background: colors?.UI?.surfaceDark,
301+
color: colors?.UI?.textSuccess
302+
//...
303+
}
304+
}
305+
306+
// component's `style.js` uses the theme variables
307+
const generateStyle = (componentTheme) => {
308+
return {
309+
button: {
310+
label: 'button',
311+
background: componentTheme.background,
312+
color: componentTheme.color
313+
//...
314+
}
315+
}
316+
}
152317
```
153318
154319
### Branding (user customizable theming)

packages/emotion/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ type: example
110110
color='primary'
111111
margin="0 0 0 small"
112112
themeOverride={(_componentTheme, currentTheme) => ({
113-
primaryBackground: currentTheme.colors.backgroundWarning,
114-
primaryBorderColor: currentTheme.colors.backgroundLightest,
113+
primaryBackground: currentTheme.colors.primitives.orange57,
114+
primaryBorderColor: '#00AAA4',
115115
borderWidth: currentTheme.borders.widthLarge,
116116
borderStyle: 'dashed'
117117
})}

0 commit comments

Comments
 (0)