Theming
Bento has been designed on top of a set of semantic design tokens which define the colors, typography and the general aspect of the Design System. Each token corresponds to a CSS variable whose value can be changed at your will.
In the quick start instructions we imported two different stylesheets for our default app:
index.css
contains the style for all the Bento components and it references the theme CSS variables. This file must always be imported in your app.defaultTheme.css
defines a default theme for the library, i.e. it assigns a default value to each of those variables (this is the theme that is also used by the examples in the documentation).
By importing the defaultTheme.css
stylesheet, we're setting a global theme, i.e. the values for the
theme CSS variables will be attached to the :root
CSS pseudo-class.
There are different ways to define a theme for your DS created using Bento:
- defining a global theme using the
makeGlobalBentoTheme
utility - using the BentoProvider/BentoThemeProvider utilities
- using CSS variables directly
Defining a global theme using the makeGlobalBentoTheme
utility
Bento offers a makeGlobalBentoTheme
utility that can be used to create a new .css theme file that can be imported globally as we did previously with the defaultTheme.css
.
The makeGlobalBentoTheme
utility is just a wrapper around the createGlobalTheme
function provided by Vanilla Extract, a CSS library used internally by Bento, which uses TypeScript to author styles.
We will assume you already set-up Vanilla Extract for you project following its official documentation.
Using the makeGlobalBentoTheme
utility in a .css.ts
file, you can create a new theme by setting a value for each of the design tokens bento defines:
import { makeGlobalBentoTheme } from "@buildo/bento-design-system";
makeGlobalBentoTheme({
fontFamily: {
default: "Arial",
},
});
You're not forced to set a value for each of the design tokens Bento defines.
For each of the design tokens that are not explicitly set in the makeGlobalBentoTheme
call, Bento will use the value defined by the default theme.
If you define a custom theme, you must ensure all the fonts you want to use in it are made available in your app (e.g. by importing the correct Google Fonts). If you don't want to override the default fonts used by Bento, you can import them with the following line:
import "@buildo/bento-design-system/defaultFonts.css";
This is not needed if you're already importing the defaultTheme.css
file, since it already includes the default fonts.
If you correctly set-up Vanilla Extract in your build pipeline as described in the suggested project structure, the build of your design-system package will produce a theme.css
file you can import in your final app in place of the defaultTheme.css
file.
Customizing the theme using BentoProvider and BentoThemeProvider
The BentoProvider
component accepts an optional theme
prop you can use to pass a custom theme for your DS.
When a value for the theme
prop is provided, the app will be wrapped in a Box
element defining the theme CSS variables for all its descendents.
Similar to the makeGlobalBentoTheme
utility, Bento offers also a makeBentoTheme
utility that can be use to create a local theme to be passed to the BentoProvider
.
import { makeBentoTheme } from "@buildo/bento-design-system";
export const theme = makeBentoTheme({
fontFamily: {
default: "Arial",
},
});
Unlike the global themes created with makeGlobalBentoTheme
, the theme created with makeBentoTheme
will not be applied globally.
The utility will instead return a className that can be passed to the BentoProvider
component and that will be applied to the Box
element created by it.
import { BentoProvider } from "@buildo/bento-design-system";
import { theme } from "design-system/lib/theme.css.ts";
export function App() {
return <BentoProvider theme={theme}>...</BentoProvider>;
}
Using the BentoProvider
to apply the theme instead of importing a global theme is recommended in case you need an easy way to switch between different themes created for your DS.
You can indeed create multiple versions (e.g. a light and a dark version) of your theme using makeBentoTheme
:
import { makeBentoTheme } from "@buildo/bento-design-system";
import { vars } from "@buildo/bento-design-system";
export const lightTheme = makeBentoTheme({
/*...*/
});
export const darkTheme = makeBentoTheme({
/*...*/
});
and then switch between them in your app by changing the theme
prop passed to the BentoProvider
component:
import { lightTheme, darkTheme } from "design-system";
// Hypothetical utility for retrieving the user preferences
import { useUserPreferences } from "../utils/useUserPreferences";
export function App() {
const { colorScheme } = useUserPreferences();
return (
<BentoProvider theme={colorScheme === "dark" ? darkTheme : lightTheme}>Hello!</BentoProvider>
);
}
You can also use the BentoProvider
to partially override a global theme imported in your app, by passing an object to the theme
prop with the partial definition of the design tokens you want to override:
import "@buildo/bento-design-system/defaultTheme.css";
import { BentoProvider } from "@buildo/bento-design-system";
export function App() {
return <BentoProvider theme={{ fontFamily: { default: "Arial" } }}>Hello!</BentoProvider>;
}
In addition to the BentoProvider
, Bento also offers a BentoThemeProvider
component which can be used to apply a theme to a single component or a subtree of components.
You can have multiple theme providers in your app, each one applying a different theme to a different part of the app.
Similar to the BentoProvider
component, the BentoThemeProvider
accepts a theme
prop which can be either a theme className created with makeBentoTheme
, or a partial definition of the design tokens that will override the theme defined in the parent providers.
Customizing the theme using plain CSS
As we discussed, Bento's theme is a collection of CSS variables, which you can override using CSS.
This option is available but not recommended, as it's easy to forget or misspell a variable without any warning.
You can either import the default theme and then override some of the default values using an additional stylesheet, or completely replace defaultTheme.css
with your own stylesheet defining a value for each of the Bento variables.
import "@buildo/bento-design-system/index.css";
import "./theme.css";
/* Import this file if you want to start from the defaultTheme and only override some variables */
@import "@buildo/bento-design-system/defaultTheme.css";
:root {
/* change the brand primary color */
--bento-brandColor-brandPrimary: green;
/* ... */
}
You can get a complete list of all the existing CSS variables by looking at the default theme.