Theming

Setup

Managing design tokens

Design systems establish a consistent user experience across platforms. They are built upon tokens, which store information about branding colors, typography and more.

Firstly, define a theme, preferably by overriding the default tokens:

theme.treat.js
import { createTheme, defaultTokens } from 'glaze';
export default createTheme({
...defaultTokens,
scales: {
...defaultTokens.scales,
color: { primary: '#d8366b' }, // Example for customization
},
});
note

Keeping the runtime as small as possible, only a few tokens (breakpoints, shorthands and aliases) are embedded into production JavaScript bundles. Other values can only be accessed exclusively for styling, as shown in usage.

Apply the theme through <ThemeProvider>, by wrapping the component tree:

import { ThemeProvider } from 'glaze';
import theme from './theme.treat';
export default function Layout({ children }) {
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
tip

The Gatsby plugin for glaze does this out of the box.

Precise autocompletion

Being written in TypeScript, glaze offers extensive type safety. To activate theme-agnostic code suggestions, include the following snippet in your project:

treat.d.ts
import { tokens } from './theme.treat'; // The previously written theme
declare module 'treat/theme' {
type Tokens = typeof tokens;
export interface Theme extends Tokens {}
}

Static style extraction

A single-purpose CSS class needs to be generated for each design token at build time. This can be set up by following the instructions of treat.

tip

Multiple integrations are available for treat, including a Gatsby plugin and a Next.js plugin.

Afterwards, selector-based CSS rules may be created with globalStyle() in *.treat.{js|ts} files. They have to be applied as a side effect, e.g. from a top-level layout component:

import './globalStyles.treat'; // {js|ts} file extensions may be omitted

Usage

export default function Component() {
return (
<p
sx={{
px: 4, // Sets `padding-left` and `padding-right` to `1rem` (from theme)
color: 'primary', // Sets color to `#d8366b` (from theme)
backgroundColor: 'red', // Non-tokens are applied as raw CSS values
}}
>
Hello, world!
</p>
);
}

How it works

At first, sx tries mapping themed values to statically generated CSS class names. Unresolved rules are injected at runtime and detached when no components reference them anymore.

Rule handling

  1. Transform each alias to its corresponding CSS property name or custom shorthand.
  2. Resolve values from a scale if available.
    • Each custom shorthand's associated CSS properties are resolved one by one.
note

Aliases and shorthands can be combined. For instance, px could be an alias for the paddingX shorthand.

Example

Heavily influenced by Tailwind CSS, the default theme contains settings like below:

import { createTheme } from 'glaze';
export default createTheme({
scales: {
spacing: { 4: '1rem' },
},
shorthands: {
paddingX: ['paddingLeft', 'paddingRight'],
},
aliases: {
px: 'paddingX',
},
matchers: {
paddingLeft: 'spacing',
paddingRight: 'spacing',
},
});

Entries of a style object passed to sx are matched to CSS rules as shown:

  1. { px: 4 }
  2. { paddingX: 4 }, after transforming aliases
  3. { paddingLeft: 4, paddingRight: 4 }, after unfolding custom shorthands
  4. { paddingLeft: '1rem', paddingRight: '1rem' }, after applying matchers