FieldCraftDocsServicesBlogWork With Me →

Theming & Presets

Customize form appearance with themes and presets.

FieldCraft uses a theme object that maps to CSS custom properties. Pass a built-in preset or define your own — every color, font, radius, and spacing value is customizable.

Using a Preset

import { FormEngineRenderer } from "@squaredr/fieldcraft-react";
import { darkPreset } from "@squaredr/fieldcraft-react";

<FormEngineRenderer schema={schema} theme={darkPreset} onSubmit={handleSubmit} />

Available Presets

PresetImportDescription
CleancleanPresetTeal primary, comfortable spacing, subtle design. The default.
ModernmodernPresetIndigo primary, larger fonts, centered layout, generous spacing.
DarkdarkPresetCyan primary on dark background, dark surface colors.
High ContrasthighContrastPresetBlue primary, large fonts, spacious layout, high contrast borders.
ClinicalclinicalPresetSky blue primary, minimal styling, bordered sections.
PlayfulplayfulPresetPink primary, fully rounded corners, warm background.

Theme Structure

A FormEngineTheme has five sections:

type FormEngineTheme = {
colors: {
primary: string;
primaryForeground: string;
secondary: string;
secondaryForeground: string;
error: string;
errorForeground: string;
warning: string;
success: string;
surface: string;
background: string;
text: string;
textMuted: string;
textDisabled: string;
border: string;
borderFocus: string;
inputBackground: string;
};
typography: {
fontFamily: string;
scale: number; // Base multiplier (e.g. 1.0)
questionSize: string; // e.g. "1.125rem"
labelSize: string; // e.g. "0.875rem"
helpTextSize: string; // e.g. "0.8125rem"
bodySize: string; // e.g. "0.9375rem"
};
shape: {
radius: "none" | "sm" | "md" | "lg" | "full";
inputRadius: string; // e.g. "8px"
buttonRadius: string;
cardRadius: string;
};
spacing: {
base: number; // Pixels
sectionGap: number;
fieldGap: number;
inputPaddingX: number;
inputPaddingY: number;
};
layout: {
maxWidth: string; // e.g. "640px"
alignment: "left" | "center";
progressPosition: "top" | "none";
sectionLayout: "card" | "bordered" | "flat";
};
};

Custom Theme

Spread a preset and override the values you want:

import { cleanPreset } from "@squaredr/fieldcraft-react";

const myTheme: FormEngineTheme = {
...cleanPreset,
colors: {
...cleanPreset.colors,
primary: "#6366f1", // Indigo
primaryForeground: "#ffffff",
background: "#fafafa",
},
shape: {
...cleanPreset.shape,
radius: "lg",
},
layout: {
...cleanPreset.layout,
maxWidth: "720px",
alignment: "center",
},
};

CSS Custom Properties

The theme is converted to CSS custom properties at runtime via themeToCssVars(). All properties use the --fe- prefix and are also aliased to shadcn/ui variable names for compatibility.

Color Variables

FieldCraft Variableshadcn Alias
--fe-color-primary--primary
--fe-color-primary-foreground--primary-foreground
--fe-color-secondary--secondary
--fe-color-error--destructive
--fe-color-surface--card, --popover, --accent
--fe-color-background--background, --muted
--fe-color-text--foreground
--fe-color-text-muted--muted-foreground
--fe-color-border--border, --input
--fe-color-border-focus--ring

Typography Variables

VariableDescription
--fe-font-familyFont stack
--fe-font-scaleBase size multiplier
--fe-font-questionQuestion label size
--fe-font-labelInput label size
--fe-font-helpHelp text size
--fe-font-bodyBody text size

Shape & Spacing Variables

VariableMapped From
--fe-radius / --radiusshape.radius (none→0px, sm→4px, md→8px, lg→12px, full→9999px)
--fe-radius-inputshape.inputRadius
--fe-radius-buttonshape.buttonRadius
--fe-radius-cardshape.cardRadius
--fe-spacing-basespacing.base (px)
--fe-spacing-section-gapspacing.sectionGap (px)
--fe-spacing-field-gapspacing.fieldGap (px)

ThemeProvider

If you're building a custom UI with hooks instead of FormEngineRenderer, wrap your form in FormEngineThemeProvider:

import {
FormEngineThemeProvider,
useTheme,
darkPreset,
} from "@squaredr/fieldcraft-react";

function MyCustomForm() {
return (
<FormEngineThemeProvider theme={darkPreset}>
<FormContent />
</FormEngineThemeProvider>
);
}

function FormContent() {
const theme = useTheme();
// theme.colors.primary, theme.typography.fontFamily, etc.
return <div>...</div>;
}

Overriding with CSS

Since all styling flows through CSS variables, you can override any value in a plain stylesheet:

.my-form-container {
--fe-color-primary: #8b5cf6;
--fe-color-background: #0f0f0f;
--fe-radius: 16px;
--fe-spacing-field-gap: 24px;
}