Skip to content

Commit 6d281b6

Browse files
author
Brijesh Bittu
committed
Add theming doc
1 parent c73f9a4 commit 6d281b6

File tree

1 file changed

+259
-0
lines changed

1 file changed

+259
-0
lines changed

docs/src/content/features/theming.mdx

+259
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
# Theming
2+
3+
<Subtitle>Learn how to apply themes to your application using Pigment CSS.</Subtitle>
4+
<Meta
5+
name="description"
6+
content="Learn how to apply themes to your application using Pigment CSS."
7+
/>
8+
9+
Theming in Pigment CSS revolves around managing CSS tokens in your code and using them to style your application.
10+
11+
## Theme Object
12+
13+
In Pigment CSS, a theme is a JavaScript object that contains a collection of CSS tokens and values. These tokens can represent anything from colors and spacing units to typography scales and breakpoints. The theme object serves as a central source of design tokens that you can consistently use throughout your application's styles. Here's how to create a theme object:
14+
15+
```ts title="src/theme.ts"
16+
// Example theme object
17+
const theme = {
18+
colors: {
19+
primary: '#6366f1',
20+
secondary: '#ec4899',
21+
background: '#ffffff',
22+
text: '#1f2937',
23+
},
24+
space: {
25+
sm: '0.5rem',
26+
md: '1rem',
27+
lg: '1.5rem',
28+
},
29+
fontSizes: {
30+
body: '1rem',
31+
heading: '1.5rem',
32+
display: '2rem',
33+
},
34+
};
35+
```
36+
37+
To use this theme, pass the `theme` object in the `pigmentConfig` object:
38+
39+
```ts title="bundler.config.ts"
40+
import { PigmentCSSConfig } from '@pigment-css/plugin/<bundler>';
41+
import { theme } from './src/theme';
42+
43+
const pigmentConfig: PigmentCSSConfig = {
44+
theme: theme,
45+
};
46+
```
47+
48+
## Accessing Theme in CSS
49+
50+
The `theme` object is automatically provided to the `styled`, `css`, and `keyframes` function callbacks as a key in the first argument, making it easy to reference your design tokens:
51+
52+
### JS Object Syntax
53+
54+
```tsx title="src/components/Button.tsx"
55+
import { styled, css } from '@pigment-css/react';
56+
57+
// Using theme in styled component
58+
const Button = styled('button')(({ theme }) => ({
59+
backgroundColor: theme.colors.primary,
60+
padding: `${theme.space.sm} ${theme.space.md}`,
61+
fontSize: theme.fontSizes.body,
62+
63+
'&:hover': {
64+
backgroundColor: theme.colors.secondary,
65+
},
66+
}));
67+
68+
// Using theme in css function
69+
const dynamicStyles = css(({ theme }) => ({
70+
color: theme.colors.text,
71+
marginBottom: theme.space.lg,
72+
}));
73+
```
74+
75+
```css title="Generated css"
76+
.button {
77+
background-color: var(--colors-primary);
78+
padding: var(--space-sm) var(--space-md);
79+
font-size: var(--fontSizes-body);
80+
}
81+
82+
.button:hover {
83+
background-color: var(--colors-secondary);
84+
}
85+
86+
.dynamic-styles {
87+
color: var(--colors-text);
88+
margin-bottom: var(--space-lg);
89+
}
90+
```
91+
92+
### Tagged-template syntax
93+
94+
While this isn't technically a tagged template literal, it provides a way to use theme values within a string template:
95+
96+
```tsx title="src/components/Button.tsx"
97+
import { styled } from '@pigment-css/react-new';
98+
99+
const Button = styled('button')(({ theme }) => `
100+
background-color: ${theme.colors.primary};
101+
padding: ${theme.space.sm} ${theme.space.md};
102+
font-size: ${theme.fontSizes.body};
103+
104+
&:hover {
105+
background-color: ${theme.colors.secondary};
106+
}
107+
`;
108+
```
109+
110+
The generated css would be the same as the one in the [JS Object Syntax](#js-object-syntax) section.
111+
112+
### The `t()` function
113+
114+
The `t()` function is a utility that you can import from `@pigment-css/react-new`. It provides a convenient way to access theme values without writing callback functions. You can use it with both JS object syntax and string template syntax:
115+
116+
```tsx title="src/components/Button.tsx"
117+
import { t } from '@pigment-css/react-new';
118+
119+
const Button = styled('button')`
120+
background-color: ${t('colors.primary')};
121+
padding: ${t('space.sm')} ${t('space.md')};
122+
font-size: ${t('fontSizes.body')};
123+
124+
&:hover {
125+
background-color: ${t('colors.secondary')};
126+
}
127+
`;
128+
```
129+
130+
Or with JS object syntax:
131+
132+
```tsx title="src/components/Button.tsx"
133+
import { t } from '@pigment-css/react-new';
134+
135+
const Button = styled('button')({
136+
backgroundColor: t('colors.primary'),
137+
padding: `${t('space.sm')} ${t('space.md')}`,
138+
fontSize: t('fontSizes.body'),
139+
140+
'&:hover': {
141+
backgroundColor: t('colors.secondary'),
142+
},
143+
});
144+
```
145+
146+
When TypeScript is configured (as explained below), you'll get autocomplete suggestions and type checking when using the `t()` function.
147+
148+
## Type Safety
149+
150+
Pigment CSS is built with TypeScript in mind and provides full type safety for your theme object. To enable autocomplete suggestions and type checking, you can augment the `Theme` interface from `@pigment-css/react-new` with your own theme type:
151+
152+
```tsx title="theme.ts"
153+
const theme = {
154+
// theme items as defined above
155+
};
156+
157+
export type Theme = typeof theme;
158+
```
159+
160+
```tsx title="augment.d.ts"
161+
import { styled } from '@pigment-css/react';
162+
import type { Theme as MyTheme } from './theme';
163+
164+
declare module '@pigment-css/react-new' {
165+
interface Theme extends MyTheme {}
166+
}
167+
```
168+
169+
Remember to include `augment.d.ts` in the `include` array of your `tsconfig.json` file.
170+
171+
## How it works
172+
173+
When you pass a `theme` object in your `pigmentConfig`, Pigment CSS does two things:
174+
175+
1. Replaces all the primitive values in the `theme` object (no matter the nesting level) with the a css variable string. This variable is a string generated from the paths in the object to access the value. This new theme object is what you actually get in the callback arguments of the `styled`, `css`, and `keyframes` functions.
176+
2. Generates a css string with all the css variables generated in step 1 with the values being the ones in the `theme` object. This css is added to the `:root` selector by default and then injected into the app through the `@pigment-css/react-new/styles.css` import added into the app entry point as instructed in the [integrations](/overview/integrations) guide.
177+
178+
For the `theme` declared [above](#theme-object), Pigment CSS will generate the following css:
179+
180+
```css title="@pigment-css/react-new/styles.css"
181+
:root {
182+
--colors-primary: #6366f1;
183+
--colors-secondary: #ec4899;
184+
--colors-background: #ffffff;
185+
--colors-text: #1f2937;
186+
--space-sm: 0.5rem;
187+
--space-md: 1rem;
188+
--space-lg: 1.5rem;
189+
--fontSizes-body: 1rem;
190+
--fontSizes-heading: 1.5rem;
191+
--fontSizes-display: 2rem;
192+
}
193+
```
194+
195+
and the corresponding theme object that is available in the callback argument is:
196+
197+
```tsx title="Generated theme"
198+
const theme = {
199+
colors: {
200+
primary: 'var(--colors-primary)',
201+
secondary: 'var(--colors-secondary)',
202+
background: 'var(--colors-background)',
203+
text: 'var(--colors-text)',
204+
},
205+
space: {
206+
sm: 'var(--space-sm)',
207+
md: 'var(--space-md)',
208+
lg: 'var(--space-lg)',
209+
},
210+
fontSizes: {
211+
body: 'var(--fontSizes-body)',
212+
heading: 'var(--fontSizes-heading)',
213+
display: 'var(--fontSizes-display)',
214+
},
215+
};
216+
```
217+
218+
As an example, you can see the theme tokens of Pigment CSS docs by opening the devtools and then selecting the `html` element. The actual `theme` object is declared [here](https://github.com/mui/pigment-css/blob/master/docs/src/theme.ts#L28).
219+
220+
## Utilities
221+
222+
Besides being a collection of css tokens, the `theme` object can also contain extra utilities that you can use to facilitate css generation. For example, you can add a breakpoint utility to the `theme` and then use it in your css like this:
223+
224+
```tsx title="src/theme.ts"
225+
const BREAKPOINTS = {
226+
xs: '32rem',
227+
sm: '40rem',
228+
} as const;
229+
230+
const theme = {
231+
// ... theme tokens
232+
breakpoints: {
233+
gt(key: keyof typeof BREAKPOINTS) {
234+
return `(min-width: ${BREAKPOINTS[key]})`;
235+
},
236+
lt(key: keyof typeof BREAKPOINTS) {
237+
return `(max-width: ${BREAKPOINTS[key]})`;
238+
},
239+
between(from: keyof typeof BREAKPOINTS, to: keyof typeof BREAKPOINTS) {
240+
return `(min-width: ${BREAKPOINTS[from]}) and (max-width: ${BREAKPOINTS[to]})`;
241+
},
242+
},
243+
};
244+
```
245+
246+
Now you can use the `breakpoints` utility in your css like this:
247+
248+
```tsx title="src/components/Button.tsx"
249+
const Button = styled('button')(({ theme }) => ({
250+
[theme.breakpoints.gt('sm')]: {
251+
padding: `${theme.space.sm} ${theme.space.md}`,
252+
},
253+
}));
254+
```
255+
256+
All of the above methods are only available for styling. They are not part of the final bundle in any way.
257+
258+
> [!NOTE]
259+
> Pigment CSS is not opinionated about the utilities or structure of the `theme` object. You can add whatever you want to it. Libraries built on top of Pigment CSS might add their own utilities or recommend a certain structure on the `theme` object.

0 commit comments

Comments
 (0)