Theming & Branding
@theatrical/react ships a warm parchment design system as its default — warm backgrounds, burnt orange accents, deep navy structure. Every visual value is a token. This guide shows how to adapt those tokens to your brand without touching component internals.
How the token system works
TheatricalThemeProvider accepts an overrides prop containing partial token overrides. Tokens are organised into namespaces (colors, typography, spacing, radii, shadows, transitions). A partial override merges within each namespace — passing { colors: { accent: '#e60026' } } changes only the accent color; all other color tokens keep their default values.
import { TheatricalThemeProvider } from '@theatrical/react';
export function App() { return ( <TheatricalThemeProvider overrides={{ colors: { accent: '#e60026' } }}> <YourApp /> </TheatricalThemeProvider> );}Color tokens
The full color palette with their default values:
| Token | Default | Role |
|---|---|---|
colors.accent | #D4622B | Burnt orange — primary CTA, selection highlight, brand signature |
colors.accentMuted | #B8532A | Muted accent for hover states |
colors.bg | #F0EDE6 | Page background — warm parchment |
colors.surface | #F5F0E1 | Card and panel backgrounds — cream |
colors.surfaceRaised | #EBE6DA | Interactive surface hover state |
colors.border | #D6D0C4 | Subtle dividers and outlines |
colors.text | #1A1A1A | Primary text — ink, never pure black |
colors.textMuted | #8A8578 | Secondary text, labels, metadata — warm grey |
colors.textDisabled | #B8B3A8 | Disabled state text |
colors.success | #22c55e | Confirmation states |
colors.warning | #D4622B | Caution states |
colors.error | #C4391D | Error and destructive states — rust |
Seat states have their own tokens — seatAvailable (#1B2D4F), seatSelected (#D4622B), seatTaken (#D6D0C4), seatPremium (#C9922A), seatWheelchair (#2A6F97), and seatCompanion (#52B788).
Overriding for your brand
// Swap accent to deep navy for a structural toneconst overrides = { colors: { accent: '#1B2D4F', accentMuted: '#15243F', },};// Event cinema red accent — rust from the paletteconst overrides = { colors: { accent: '#C4391D', accentMuted: '#A83018', },};// Invert for a dark-background deploymentconst overrides = { colors: { bg: '#1A1A1A', surface: '#242420', surfaceRaised: '#2E2E28', border: '#3D3830', text: '#F0EDE6', textMuted: '#8A8578', textDisabled: '#4A4A4A', accent: '#D4622B', accentMuted: '#B8532A', },};Typography tokens
| Token | Default | Description |
|---|---|---|
typography.fontFamily | 'Inter', -apple-system, … | Body and UI text — clean, stays out of the way |
typography.fontFamilyHeading | 'Space Grotesk', -apple-system, … | Headlines — tight tracking, poster energy |
typography.fontFamilyMono | 'JetBrains Mono', … | Labels, metadata, reference codes — archival, systematic |
typography.sizes | xs–display (0.75rem–2rem) | Type scale, keyed by name |
typography.weights | regular–bold (400–700) | Font weights |
typography.lineHeights | tight 1.25 · normal 1.5 · relaxed 1.75 | Line-height scale |
The default type stack pairs Space Grotesk for compressed, confident headings with Inter for clean body text and JetBrains Mono for systematic labels:
// Override with your own typeface pairconst overrides = { typography: { fontFamily: '"DM Sans", system-ui, sans-serif', fontFamilyHeading: '"DM Sans", system-ui, sans-serif', },};Spacing and radii
The spacing scale is a set of unitless pixel values. All component layout is derived from it:
| Token | Default |
|---|---|
spacing.xs | 4 |
spacing.sm | 8 |
spacing.md | 16 |
spacing.lg | 24 |
spacing.xl | 32 |
spacing.xxl | 48 |
Border radii control component roundness (also unitless pixels):
| Token | Default | Used by |
|---|---|---|
radii.sm | 4 | Badges, chips |
radii.md | 8 | Cards, buttons |
radii.lg | 12 | Modals, panels |
radii.full | 9999 | Pill buttons, avatars |
For a sharper, more geometric look (common in European arthouse cinemas):
const overrides = { radii: { sm: 2, md: 4, lg: 6, full: 4, // even pill buttons become slightly squared },};Applying a complete brand theme
This example wires a full custom theme in the react-ticketing template. Create src/brand.ts:
export const brandOverrides = { colors: { accent: '#C4391D', accentMuted: '#A83018', bg: '#F0EDE6', surface: '#F5F0E1', border: '#D6D0C4', }, typography: { fontFamilyHeading: '"Space Grotesk", system-ui, sans-serif', }, radii: { md: 4, lg: 8, },};Then pass it to the provider in src/App.tsx:
import { TheatricalThemeProvider } from '@theatrical/react';import { brandOverrides } from './brand';
export default function App() { return ( <TheatricalThemeProvider overrides={brandOverrides}> {/* ... */} </TheatricalThemeProvider> );}Reading tokens in your own components
The resolved tokens are available via useTheme():
import { useTheme } from '@theatrical/react';
function PriceTag({ amount }: { amount: number }) { const { colors } = useTheme(); return ( <span style={{ color: colors.accent, fontWeight: 700 }}> {new Intl.NumberFormat('en-NZ', { style: 'currency', currency: 'NZD' }).format(amount)} </span> );}This keeps custom components visually consistent with the token system — if you change the accent color in the provider, your component updates automatically.