Theming
Customise colours, typography, spacing, and shape with theme objects, CSS custom properties, and auto-inherited host page styles.
How theming works
FieldCraft's renderer uses CSS custom properties (--background, --foreground, --primary, etc.) to control visual appearance. There are three ways to theme a form, from simplest to most flexible:
- Auto-inherit — if your host page defines shadcn-style CSS variables at
:root, the renderer picks them up automatically. No code needed. - Theme object — pass a
FormEngineThemeto thethemeprop for explicit control. - CSS overrides — target
--fc-*variables in your own stylesheets.
Auto-inherit from host page
If your page already defines CSS custom properties like --background, --foreground, --primary, --border, etc. (the standard shadcn/ui pattern), FormEngineRenderer inherits them automatically:
import { FormEngineRenderer } from '@squaredr/fieldcraft-react'// No theme prop needed — inherits from your page's CSS variables<FormEngineRenderer schema={schema} onSubmit={handleSubmit} />This also applies to FieldCraft Pro components (FormBuilder, ResponseViewer, ThemeEditor) — they all auto-inherit from the host page's CSS variables and follow dark/light mode changes.
Custom theme object
Build a FormEngineTheme to control every visual aspect. All properties are optional — undefined values fall back to the host page's CSS variables or built-in defaults.
import type { FormEngineTheme } from '@squaredr/fieldcraft-react'const myTheme: FormEngineTheme = { colors: { primary: '#0066cc', primaryForeground: '#ffffff', secondary: '#f0f0f0', secondaryForeground: '#333333', error: '#dc2626', errorForeground: '#ffffff', warning: '#f59e0b', success: '#22c55e', surface: '#ffffff', background: '#fafafa', text: '#111111', textMuted: '#666666', textDisabled: '#aaaaaa', border: '#e0e0e0', borderFocus: '#0066cc', inputBackground: '#ffffff', }, typography: { fontFamily: 'Inter, system-ui, sans-serif', scale: 'comfortable', // 'compact' | 'comfortable' | 'spacious' questionSize: '1rem', labelSize: '0.875rem', helpTextSize: '0.75rem', bodySize: '0.875rem', }, shape: { radius: 'md', // 'none' | 'sm' | 'md' | 'lg' | 'full' inputRadius: '6px', buttonRadius: '6px', cardRadius: '8px', }, spacing: { base: 16, sectionGap: '2rem', fieldGap: '1.5rem', inputPaddingX: '12px', inputPaddingY: '8px', }, layout: { maxWidth: '640px', alignment: 'left', // 'left' | 'center' progressPosition: 'top', // 'top' | 'bottom' | 'none' sectionLayout: 'card', // 'card' | 'flat' | 'bordered' },}Pass it to the renderer:
<FormEngineRenderer schema={schema} theme={myTheme} onSubmit={handleSubmit} />Presets (Pro)
Five ready-made preset families with light and dark variants are available in FieldCraft Pro:
| Preset family | Description |
|---|---|
| Clean | Minimal, neutral colours, comfortable spacing. |
| Modern | Contemporary styling with rounded corners. |
| High Contrast | Accessibility-focused. Strong borders, large text. |
| Clinical | Professional/medical. Clean lines, clinical feel. |
| Playful | Friendly and colourful. Larger radii, warmer tones. |
import { PRESET_FAMILIES } from '@squaredr/fieldcraft-pro'// Each family has .light and .dark variantsconst theme = PRESET_FAMILIES.modern.lightconst darkTheme = PRESET_FAMILIES.modern.darkCSS custom properties
The theme is converted to CSS custom properties (--fc-*) on the form root element. You can use these variables in your own CSS:
.my-form-wrapper { border: 1px solid var(--fc-border); background: var(--fc-surface); font-family: var(--fc-font-family);}How the CSS variable chain works
Host page :root CSS variables (--background, --primary, etc.) → Inherited by FormEngineRenderer automatically → theme prop overrides specific values via inline styles → themeToCssVars() converts to --fc-* variables → shadcn/Radix components read these variables → Your custom CSS can also read themThemeProvider
For advanced use cases, wrap your app in FormEngineThemeProvider:
import { FormEngineThemeProvider } from '@squaredr/fieldcraft-react'function App() { return ( <FormEngineThemeProvider theme={myTheme}> {/* All FormEngineRenderer instances inside inherit this theme */} <FormEngineRenderer schema={form1} onSubmit={handle1} /> <FormEngineRenderer schema={form2} onSubmit={handle2} /> </FormEngineThemeProvider> )}The useTheme() hook accesses the current theme from context:
import { useTheme } from '@squaredr/fieldcraft-react'function CustomComponent() { const theme = useTheme() return <div style={{ color: theme.colors?.primary }}>Themed content</div>}Next steps
- Custom field types — register your own field components
- FormEngineRenderer — all FormEngineRenderer props