Defining colours is easy enough! In your theme.css.tsx file, you can define a flat set of colours:
colors: {
// Brand/literal colors
russet: "#AF5861",
gold: "#9B7850",
buff: "#CFCAC5",
white: "white",
black: "black",
// Semantic colors, which draw from the brand colors
// If your project requires multiple colour palettes, these should be the defaults
background: "$white",
foreground: "$russet",
highlight: "$gold",
reverse: "$black",
},
We consider it best practice to break your colours out into 'literal' and 'semantic' colours, which you can see in the above example code.
black, russet, brand, rose, grey-200 etc.background, foreground, link, faded etc are all semantic colours.Similar to any other token, you can use colour tokens directly in your styled components:
You should try your best to use semantic colours, especially on sites which use multiple colour themes.
const MyComponent = styled("div", {
color: "$foreground",
})
In the default theme.css.tsx, you'll notice a subthemes export. This is a map of subthemes, which you can use to create a new colour theme.
When you create a subtheme with createTheme(), you're actually defining a global class. The class can then be applied to any element, and the colour overrides your define within it will be inherited by all child components.
export const subthemes = {
// The 'block-editor-page' class is automatically applied
// to blocks in the Gutenberg editor, and so this theme will be
// used there automatically!
editor: createTheme("block-editor-page", {
colors: {
background: "white",
foreground: "black",
link: "$blue",
},
}),
// We're creating a 'dark-mode' subtheme
darkMode: createTheme("dark-mode", {
colors: {
background: "black",
foreground: "white",
link: "$gold",
},
}),
}
In the above example, we're defining two subthemes:
editor theme, which will be used in the Gutenberg editor, because it has the block-editor-page class which is applied to the root div of the Gutenberg UI.darkMode theme.With the latter theme, there are two ways in which we can use this:
<Card className="dark-mode">
This div will have a black background, with white text — from the subtheme
</Card>
<Card>
This div will have a background + color from the default theme
</Card>
const Card = styled('div', {
backgroundColor: '$background',
color: '$foreground'
})
useSubtheme() for global subtheming#The useSubtheme() hook which comes pre-installed, allows you to swap your entire page's theme to a subtheme, when mounting a React component — and then reverts it when the component is unmounted.
The most common usage for this is when you have a whole page or template which uses different colours to the rest of the site:
import { useSubtheme } from '@hooks/useSubtheme'
export default defineView('single-project', () => {
// The whole page will use the darkMode colours, until the user navigates to another page
useSubtheme('darkMode')
return <div>
/* ... */
</div>
})
You can also programatically swap themes, which can be useful in cases where you want to change the theme of a page during specific interactions (eg. scrolling, or clicking). Use the second optional active parameter for this.
function DarkModeToggle() {
const [darkMode, setDarkMode] = useState(false)
useSubtheme("darkMode", darkMode)
return <button onClick={() => setDarkMode(!darkMode)}>Toggle Dark mode</button>
}
Note that useSubtheme() takes the object key from the subthemes export in theme.css.tsx, rather than the class
name.