Visual Templates
SchemaForms Data ships with 20+ ready-made visual templates. You can use one as-is, override CSS variables, or register a completely new theme.
Available templates
| ID | Style | Navigation |
|---|---|---|
moderno | Card, normal spacing | Wizard |
minimalista | Flat, relaxed spacing | Wizard |
card | Card, normal | Wizard |
banner | Bordered, tabs | Tabs |
acampamento | Glassmorphism, labelled icons | Wizard |
acampamento_imersivo | Immersive glassmorphism | Wizard |
corporativo | Bordered, formal | Wizard |
festival | Vibrant glassmorphism | Wizard |
webinar | Compact card | Tabs |
retiro | Relaxed card | Wizard |
conferencia | Professional card | Wizard |
social | Friendly card | Wizard |
workshop | Bordered, vertical | Vertical |
gala | Elegant glassmorphism | Wizard |
acao | Compact card | Wizard |
podcast | Modern card | Wizard |
classico | Classic card | Wizard |
comunitario | Relaxed card | Wizard |
noturno | Dark glassmorphism | Wizard |
Applying a template
Pass the template ID to FormRenderer:
<FormRenderer schema={schema} template="acampamento" onComplete={handler} />
Or use TemplateProvider directly to wrap a component:
import { TemplateProvider } from "@schema-forms-data/templates";
<TemplateProvider templateId="noturno">
<FormRenderer schema={schema} onComplete={handler} />
</TemplateProvider>;
CSS Variables
Each template injects the following CSS variables on the form wrapper:
| Variable | Description |
|---|---|
--t-primary | Primary colour (buttons, accents) |
--t-primary-hover | Primary colour on hover |
--t-accent | Accent colour |
--t-bg | Form background colour |
--t-surface | Card/container background colour |
--t-text | Main text colour |
--t-text-muted | Secondary text colour (labels, hints) |
--t-border | Border colour |
--t-error | Error colour |
Registering a custom template
import { registerTemplate } from "@schema-forms-data/templates";
import type { FormTemplateConfig } from "@schema-forms-data/core";
// Call once at application startup
registerTemplate({
id: "my-brand",
displayName: "My Brand",
colors: {
primary: "#7c3aed",
primaryHover: "#6d28d9",
accent: "#a78bfa",
background: "#faf5ff",
surface: "#ffffff",
text: "#1e1b4b",
textMuted: "#6b7280",
border: "#ddd6fe",
error: "#dc2626",
},
layout: {
stepNavigation: "wizard",
containerStyle: "card",
spacing: "normal",
roundness: "lg",
showProgressBar: true,
showStepIndicators: true,
stepIndicatorVariant: "numbers",
stepIndicatorPosition: "top-center",
},
typography: {
fontFamily: '"Nunito", sans-serif',
stepTitleClass: "text-2xl font-bold",
stepDescClass: "text-base text-muted",
labelClass: "text-sm font-medium",
},
wrapperClass: "my-brand-wrapper",
});
Then use it in any FormRenderer:
<FormRenderer schema={schema} template="my-brand" onComplete={handler} />
Querying available templates
import {
getAllTemplates,
getTemplateConfig,
} from "@schema-forms-data/templates";
// List all templates
const all = getAllTemplates();
// [{ id: 'moderno', displayName: 'Moderno', ... }, ...]
// Get a specific template (with fallback to 'moderno')
const config = getTemplateConfig("corporativo");
Using the template context in a component
import { useTemplate } from "@schema-forms-data/templates";
function StyledButton() {
const template = useTemplate();
return (
<button
style={{
backgroundColor: template.colors.primary,
color: "#fff",
borderRadius: "8px",
}}
>
Next
</button>
);
}
FormTemplateConfig (complete type)
interface FormTemplateConfig {
id: string;
displayName: string;
colors: FormTemplateColors;
layout: FormTemplateLayout;
typography?: FormTemplateTypography;
wrapperClass?: string;
}
interface FormTemplateColors {
primary: string;
primaryHover: string;
accent: string;
background: string;
surface: string;
text: string;
textMuted: string;
border: string;
error: string;
}
interface FormTemplateLayout {
stepNavigation: "wizard" | "tabs" | "vertical";
containerStyle: "card" | "glassmorphism" | "flat" | "bordered";
spacing: "compact" | "normal" | "relaxed";
roundness: string;
showProgressBar: boolean;
showStepIndicators: boolean;
stepIndicatorVariant?: "numbers" | "icons" | "icons-labeled";
stepIndicatorPosition?: "top-center" | "top-left";
stepIndicatorOrientation?: "horizontal" | "vertical";
eventTitleStyle?: "bar" | "inline" | "hidden";
}
Template in the builder
The BuilderWrapper also accepts a template prop so the canvas preview matches what the end user will see:
<BuilderWrapper template="my-brand" schema={schema} onSave={handleSave}>
<Canvas />
</BuilderWrapper>
| card | Card, normal | Wizard |
| banner | Bordas, tabs | Tabs |
| acampamento | Glassmorphism, ícones com label | Wizard |
| acampamento_imersivo | Glassmorphism imersivo | Wizard |
| corporativo | Bordas, formal | Wizard |
| festival | Glassmorphism vibrante | Wizard |
| webinar | Card compacto | Tabs |
| retiro | Card relaxado | Wizard |
| conferencia | Card profissional | Wizard |
| social | Card amigável | Wizard |
| workshop | Bordas, vertical | Vertical |
| gala | Glassmorphism elegante | Wizard |
| acao | Card compacto | Wizard |
| podcast | Card moderno | Wizard |
| classico | Card clássico | Wizard |
| comunitario | Card relaxado | Wizard |
| noturno | Glassmorphism escuro | Wizard |
Aplicar um template
Passe o ID do template para o FormRenderer:
<FormRenderer schema={schema} template="acampamento" onComplete={handler} />
Ou use o TemplateProvider diretamente para envolver um componente:
import { TemplateProvider } from "@schema-forms-data/templates";
<TemplateProvider templateId="noturno">
<FormRenderer schema={schema} onComplete={handler} />
</TemplateProvider>;
CSS Variables
Cada template injeta as seguintes variáveis CSS no wrapper do formulário:
| Variável | Descrição |
|---|---|
--t-primary | Cor primária (botões, acentos) |
--t-primary-hover | Cor primária ao hover |
--t-accent | Cor de destaque |
--t-bg | Cor de fundo do formulário |
--t-surface | Cor de fundo dos cards/containers |
--t-text | Cor do texto principal |
--t-text-muted | Cor do texto secundário (labels, hints) |
--t-border | Cor das bordas |
--t-error | Cor de erros |
Registrar um template customizado
import { registerTemplate } from "@schema-forms-data/templates";
import type { FormTemplateConfig } from "@schema-forms-data/core";
// Chamar uma vez no início da aplicação
registerTemplate({
id: "minha-marca",
displayName: "Minha Marca",
colors: {
primary: "#7c3aed",
primaryHover: "#6d28d9",
accent: "#a78bfa",
background: "#faf5ff",
surface: "#ffffff",
text: "#1e1b4b",
textMuted: "#6b7280",
border: "#ddd6fe",
error: "#dc2626",
},
layout: {
stepNavigation: "wizard",
containerStyle: "card",
spacing: "normal",
roundness: "lg",
showProgressBar: true,
showStepIndicators: true,
stepIndicatorVariant: "numbers",
stepIndicatorPosition: "top-center",
},
typography: {
fontFamily: '"Nunito", sans-serif',
stepTitleClass: "text-2xl font-bold",
stepDescClass: "text-base text-muted",
labelClass: "text-sm font-medium",
},
wrapperClass: "minha-marca-wrapper",
});
Depois use em qualquer FormRenderer:
<FormRenderer schema={schema} template="minha-marca" onComplete={handler} />
Consultar templates disponíveis
import {
getAllTemplates,
getTemplateConfig,
} from "@schema-forms-data/templates";
// Listar todos os templates
const todos = getAllTemplates();
// [{ id: 'moderno', displayName: 'Moderno', ... }, ...]
// Buscar um template específico (com fallback para 'moderno')
const config = getTemplateConfig("corporativo");
Usar o contexto de template num componente
import { useTemplate } from "@schema-forms-data/templates";
function BotaoEstilizado() {
const template = useTemplate();
return (
<button
style={{
backgroundColor: template.colors.primary,
color: "#fff",
borderRadius: "8px",
}}
>
Avançar
</button>
);
}
FormTemplateConfig (tipo completo)
interface FormTemplateConfig {
id: string;
displayName: string;
colors: FormTemplateColors;
layout: FormTemplateLayout;
typography?: FormTemplateTypography;
wrapperClass?: string;
}
interface FormTemplateColors {
primary: string;
primaryHover: string;
accent: string;
background: string;
surface: string;
text: string;
textMuted: string;
border: string;
error: string;
}
interface FormTemplateLayout {
stepNavigation: "wizard" | "tabs" | "vertical";
containerStyle: "card" | "glassmorphism" | "flat" | "bordered";
spacing: "compact" | "normal" | "relaxed";
roundness: string;
showProgressBar: boolean;
showStepIndicators: boolean;
stepIndicatorVariant?: "numbers" | "icons" | "icons-labeled";
stepIndicatorPosition?: "top-center" | "top-left";
stepIndicatorOrientation?: "horizontal" | "vertical";
eventTitleStyle?: "bar" | "inline" | "hidden";
}
// Depois use o template registrado:
<FormRenderer schema={schema} templateKey="brand" onComplete={handler} />
Custom Field Components
For deeper customization, you can swap out individual field renderers:
import { registerFieldRenderer } from "@schema-forms-data/renderer";
import { FieldType } from "@schema-forms-data/core";
// Replace the default TEXT renderer with your own
registerFieldRenderer(FieldType.TEXT, ({ field, value, onChange, error }) => (
<div className="my-text-field">
<label>{field.label}</label>
<input
value={value ?? ""}
onChange={(e) => onChange(e.target.value)}
className={error ? "error" : ""}
/>
{error && <span className="error-msg">{error}</span>}
</div>
));
Template in the Builder
The BuilderProvider also accepts a templateKey prop, so the canvas preview matches what the end user will see:
<BuilderProvider templateKey="brand" ...>
<Canvas />
</BuilderProvider>