Skip to main content

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).
info

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.

note

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:

my-project/design-system/src/theme.css.ts
import { makeGlobalBentoTheme } from "@buildo/bento-design-system";

makeGlobalBentoTheme({
fontFamily: {
default: "Arial",
},
});
note

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.

caution

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:

my-project/src/index.ts
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.

my-project/design-system/src/theme.css.ts
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.

my-project/src/App.tsx
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:

my-project/design-system/src/theme.css.ts
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:

"my-project/app/src/App.tsx
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:

"my-project/app/src/App.tsx
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.

caution

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.

my-project/design-system/src/index.tsx
import "@buildo/bento-design-system/index.css";
import "./theme.css";
my-project/design-system/src/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;
/* ... */
}
info

You can get a complete list of all the existing CSS variables by looking at the default theme.