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';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.
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.
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:
Gap
Use the gap property on components like Stack and Inline:
Colors
Note that the
colorsprovided to the theme are only half of the picture. These colours are operated on to create thesemantic.colourtokens.
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
Functional colors
Variant colors
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.
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:
Radii
{
none: 0,
xsmall: 4,
small: 6,
medium: 8,
large: 12,
}Access radii from the theme object.
const { radii } = useTheme();Radii variants:
Sizing
Shape
Sizing can be defined numerically/unitless for pixels (24), or as a string to
provide a unit as (2.4rem).
Usage
Hook
Import the useTheme hook from the theme package.
import { useTheme } from '@balance-web/theme';Access sizing from the theme object.
Components
Various components consume the sizing keys as props.
Avatars
Avatars accept sizing keys.
Buttons and Inputs
Buttons and inputs accept a limited set of the sizing keys.
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).
Usage
Hook
Import the useTheme hook from the theme package.
import { useTheme } from '@balance-web/theme';Access spacing from the theme object.
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:
Gap
Use spacing keys for the gap property on components like Stack and Inline:
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.
Components
Various layout primitives consume the typography keys as props.
Text
The Text component supports leading.
Heading
The Heading component supports leading.