Docs
v1.3.14
GitHubSite
React / Theming

Theming

Customise colours, typography, spacing, and shape with theme objects, 6 built-in presets, and CSS custom properties.

Using a preset

Pass a built-in preset to FormRenderer:

import { FormRenderer, cleanPreset } from '@squaredr/fieldcraft-react'

<FormRenderer schema={schema} theme={cleanPreset} onSubmit={handleSubmit} />

Available presets

PresetDescription
cleanPresetMinimal, light. Neutral colours, comfortable spacing.
modernPresetContemporary styling with rounded corners.
darkPresetDark background with light text.
highContrastPresetAccessibility-focused. Strong borders, large text.
clinicalPresetProfessional/medical. Clean lines, clinical feel.
playfulPresetFriendly and colourful. Larger radii, warmer tones.

Custom theme object

Build a FormEngineTheme to control every visual aspect. All properties are optional — undefined values use the preset 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'
  },
}

Extending a preset

Spread a preset and override specific properties:

import { cleanPreset } from '@squaredr/fieldcraft-react'

const branded = {
  ...cleanPreset,
  colors: {
    ...cleanPreset.colors,
    primary: '#8b5cf6',
    borderFocus: '#8b5cf6',
  },
  typography: {
    ...cleanPreset.typography,
    fontFamily: 'Satoshi, sans-serif',
  },
}

CSS 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

Your theme object (FormEngineTheme)
    → themeToCssVars() converts to --fc-* variables
    → Applied as inline styles on the form root
    → shadcn/Radix components read --fc-* variables
    → Your custom CSS can also read them

ThemeProvider

For advanced use cases, wrap your app in FormEngineThemeProvider:

import { FormEngineThemeProvider } from '@squaredr/fieldcraft-react'

function App() {
  return (
    <FormEngineThemeProvider theme={myTheme}>
      {/* All FormRenderer instances inside inherit this theme */}
      <FormRenderer schema={form1} onSubmit={handle1} />
      <FormRenderer 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

On this page