BalanceReckon Design System
Foundations

Theme

Theming is a mechanism by which a consistent look and feel can be applied to all the components within an application.

import { makeTheme, ThemeContext, ThemeProvider, useTheme, useRawTheme, theme, themeRaw, getTextColors, getHeadingColors, getBoxBackgrounds, getBoxBorders, getDecorativeSurfaces, DEPRECATED_BUTTON_TONE_RAMP, FOCUS_RING, FORM_CONTROL_SURFACE_DISABLED, ICON_STROKE_HOVER, ICON_STROKE_PRESSED, NEUTRAL_K99_WITHOUT_TOKEN, SEGMENTED_CONTROL_DIVIDER, SURFACE_SELECTED, TABLE_CELL_BORDER_DISABLED, TABLE_ROW_TINTS, TEXT_LINK_VISITED } from '@balance-web/theme';
Loading demo…

Setup

useTheme() (used throughout this page) reads from a ThemeProvider that must be an ancestor in the tree. Most apps never call ThemeProvider directly — @reckon-web/reckon-balance-core's ReckonBalanceCore wraps its own ThemeProvider and is what's mounted at the app root. Reach for this package's ThemeProvider only if you're building something outside that setup (e.g. an isolated preview, or the design system itself).

import { ThemeProvider } from '@balance-web/theme';

Customising a theme

makeTheme(source, partial) deep-merges partial over a complete source theme (e.g. the exported lightTheme from @reckon-web/reckon-balance-theme), returning a new theme object with full type safety — only the keys you override need to be provided.

import { makeTheme } from '@balance-web/theme';

const customTheme = makeTheme(lightTheme, {
  colors: { primary: '#5a3fff' },
});

theme vs useTheme(), and themeRaw vs useRawTheme()

Every example on this page calls the useTheme() hook, which is the right choice inside a component. theme (used the same way, without the ()) is a plain module-level binding that ThemeProvider reassigns on mount — useful in non-component code (e.g. a style computed once at module scope), but it holds a default theme until a ThemeProvider has actually mounted, so prefer the hook wherever you're inside a component.

useRawTheme()/themeRaw expose the unprocessed theme — the same shape ThemeProvider was given, plus the raw themeCSSVars map — rather than the resolved values useTheme()/theme return. Component authors inside this design system reach for the raw theme more often than everyday consumers do.

Internal colour-mapping helpers

getTextColors, getHeadingColors, getBoxBackgrounds, getBoxBorders and getDecorativeSurfaces translate semantic.colour into the smaller prop vocabularies individual components expose (e.g. Text's color prop, Box's background/border props, Avatar/Tag's decorative palette). They exist so those components can be built once and stay in sync with the semantic tokens; you'll only need them directly if you're building a new Balance component.

Pending tokens

pendingTokens is an internal migration-tracking module: a small set of colour literals the design system still needs a real semantic token for. Each export is documented in its own source with the design question blocking it. These are not part of the public theming API — if you find yourself importing one, check with design first, since the value is very likely to change once its token lands.

Breakpoints

Breakpoints underpin our responsive strategy for the entire system. Breakpoints are used internally by many components and are exposed externally to allow responsive configuration.

Shape

Breakpoints can be defined numerically/unitless for pixels 1024, or as a string to provide a unit as 64em. Below is the default set:

type Breakpoints = {
  small: 576;
  medium: 768;
  large: 992;
  xlarge: 1200;
};

These are the only breakpoints that should be used for responsive styling. If your UI requires additional non-standard media queries you should work with your designer to see what solutions are possible working within the system.

Usage

Hook

Import the useMediaQuery hook from the utils package.

import { useMediaQuery } from '@balance-web/media-query';
Responsive values

To target a specific value that should change across breakpoints use the mq utility function. You can pass in a standard CSS object, and array values will be applied to their respective breakpoints.

Note that if a value is repeated across several breakpoints, a null value can be used to prevent generating unnecessary CSS.

Loading demo…

This is achieved using Emotion's facepaint library.

Min / Max

For granular control over a group of styles use the minBreak and maxBreak utility functions. They accept a single argument, which must be one of the breakpoint keys supplied to the theme.

Loading demo…

Components

Various layout primitives consume the breakpoints as props, similar to the "responsive values".

Padding and Margin

Use the padding and margin properties on the Box component. Each layout primitive extends the Box component:

Loading demo…
Gap

Use the gap property on components like Stack and Inline:

Loading demo…

Colors

Note that the colors provided to the theme are only half of the picture. These colours are operated on to create the semantic.colour tokens.

Shape

Because we perform functions on these colours they must be provided as hex values.

type Colors = {
  background: string;
  text: string;
  primary: string;
  accent: string;

  danger: string;
  warning: string;
  success: string;
  info: string;

  decorative: string[];
};

Usage

Import the useTheme hook from the theme package.

import { useTheme } from '@balance-web/theme';

You may access colors from the theme, though it's not recommended. Prefer using the resolved semantic.colour tokens, also available on the theme object.

const { colors } = useTheme();

Core colors

Loading demo…

Functional colors

Loading demo…

Variant colors

Loading demo…

Semantic colour

semantic.colour is the colour layer to build on. Tokens are named for the role they play — text.textSecondary, surface.neutral.border, reserved.critical.container.background — and are generated from the design tokens in @reckon-web/reckon-balance-theme.

Loading demo…

Shadow

{
  S100: `0px 1px 2px rgba(0, 0, 0, 0.2)`,
  S200: `0px 2px 4px rgba(0, 0, 0, 0.2)`,
  S300: `0px 2px 8px rgba(0, 0, 0, 0.2)`,
  S400: `0px 4px 16px rgba(0, 0, 0, 0.2)`,
  S500: `-8px 8px 32px rgba(0, 0, 0, 0.2)`,
}

Access shadow from the theme object.

const { shadow } = useTheme();

Shadow variants:

Loading demo…

Radii

{
  none: 0,
  xsmall: 4,
  small: 6,
  medium: 8,
  large: 12,
}

Access radii from the theme object.

const { radii } = useTheme();

Radii variants:

Loading demo…

Sizing

Shape

Sizing can be defined numerically/unitless for pixels (24), or as a string to provide a unit as (2.4rem).

Loading demo…

Usage

Hook

Import the useTheme hook from the theme package.

import { useTheme } from '@balance-web/theme';

Access sizing from the theme object.

Loading demo…

Components

Various components consume the sizing keys as props.

Avatars

Avatars accept sizing keys.

Loading demo…
Buttons and Inputs

Buttons and inputs accept a limited set of the sizing keys.

Loading demo…

Spacing

The default theme implements a base unit of 4px.

Shape

Spacing can be defined numerically/unitless for pixels (4), or as a string to provide a unit as (0.4rem).

Loading demo…

Usage

Hook

Import the useTheme hook from the theme package.

import { useTheme } from '@balance-web/theme';

Access spacing from the theme object.

Loading demo…

Components

Various layout primitives consume the spacing keys as props.

Padding and Margin

Use the padding and margin properties on the Box component. Each layout primitive extends the Box component:

Loading demo…
Gap

Use spacing keys for the gap property on components like Stack and Inline:

Loading demo…

Typography

Shape

Below is the default typography configuration:

type Typography = {
  fontFamily: {
    monospace: 'Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace';
    body: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif';
    heading: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif';
  };
  fontSize: {
    xsmall: '0.75rem';
    small: '0.875rem';
    medium: '1rem';
    large: '1.125rem';
    xlarge: '1.25rem';
    xxlarge: '1.5rem';
    xxxlarge: '1.875rem';
    xxxxlarge: '2.25rem';
    xxxxxlarge: '3rem';
    xxxxxxlarge: '4rem';
  };
  fontWeight: {
    regular: 400;
    medium: 500;
    semibold: 600;
    bold: 700;
    heavy: 800;
  };
  leading: {
    tighter: 1;
    tight: 1.2;
    base: 1.4;
    loose: 1.6;
    looser: 1.8;
  };
};

Usage

Hook

Import the useTheme hook from the theme package.

import { useTheme } from '@balance-web/theme';

Access typography from the theme object.

Loading demo…

Components

Various layout primitives consume the typography keys as props.

Text

The Text component supports leading.

Loading demo…
Heading

The Heading component supports leading.

Loading demo…

On this page