Pular para o conteúdo principal

FormRenderer

O componente principal que renderiza um FormSchema como um formulário multi-step ao vivo.

Import

import { FormRenderer } from "@schema-forms-data/renderer";
// ou
import { FormRenderer } from "@schema-forms-data/react";

Props

Obrigatórias

PropTipoDescrição
schemaFormSchemaA definição do formulário. Veja Core Types.

Eventos

PropTipoDescrição
onSubmitStep(stepIndex: number, data: Record<string, unknown>) => Promise<void>Chamado quando o usuário avança cada step. Use para salvar rascunhos.
onComplete(data: Record<string, unknown>) => Promise<void>Chamado no submit final com todos os valores acumulados de todos os steps.
onValuesChange(values: Record<string, unknown>) => voidChamado a cada mudança de campo no step atual — útil para autosave.

Visual

PropTipoPadrãoDescrição
formTitlestringundefinedTítulo exibido no topo do formulário.
templatestring | null"moderno"Chave do template. Veja Templates Customizados.
classNamestringundefinedClasse CSS extra aplicada ao wrapper raiz.
StepIndicatorReact.ComponentType<StepIndicatorProps>built-inComponente de indicador de step customizado. Veja abaixo.

Dados

PropTipoPadrãoDescrição
initialValuesRecord<string, unknown>{}Pré-preenche valores dos campos quando o formulário carrega.
initialStepnumber0Inicia o formulário em um step específico (base 0).
externalDataRecord<string, unknown>{}Dados disponíveis para interpolação de template vars ({{evento.nome}}) e condicionais source: 'evento'.
fieldErrorsRecord<string, string>{}Erros de servidor por campo (ex: de uma resposta 422) definidos após o envio.

Integrações

PropTipoDescrição
uploadFile(file: File, fieldName: string, onProgress?: (pct: number) => void) => Promise<string>Chamado quando o usuário seleciona um arquivo. Retorne o uploadId.
deleteUploadedFile(uploadId: string) => Promise<void>Chamado automaticamente antes de substituir um arquivo, para deletar o anterior. Erros são silenciados.
cepLookup(cep: string, signal?: AbortSignal) => Promise<CepLookupResult>Busca de CEP. Usa a API pública ViaCEP por padrão.
resolveTermsUploadUrl(uploadId: string) => Promise<string>Resolve a URL de preview de um PDF de termos a partir de um uploadId.
fieldResolversFieldResolversProps dinâmicas por campo — carregadas em tempo de render. Veja Injeção.
validatorMapperValidatorMapperFunções validadoras assíncronas customizadas. Veja Validação.
componentMapperComponentMapperSubstitui o componente built-in de qualquer tipo de campo. Veja Component Mapper.
paymentMethodOptions{ porDia?: PaymentOption[]; todosOsDias?: PaymentOption[] }Opções customizadas para o campo payment_method.

Exemplo de uso

import { FormRenderer } from "@schema-forms-data/renderer";

<FormRenderer
schema={schema}
formTitle="Cadastro"
template="moderno"
externalData={{ "evento.nome": "Acampamento 2026", "evento.valor": 5000 }}
initialValues={{ nome: "João" }}
uploadFile={async (file, fieldName, onProgress) => {
const form = new FormData();
form.append("file", file);
form.append("campo", fieldName);
const res = await fetch("/api/upload", { method: "POST", body: form });
const { id } = await res.json();
return id;
}}
deleteUploadedFile={async (uploadId) => {
await fetch(`/api/upload/${uploadId}`, { method: "DELETE" });
}}
cepLookup={async (cep) => {
const res = await fetch(`/api/cep/${cep}`);
return res.json(); // { logradouro, bairro, cidade, estado }
}}
resolveTermsUploadUrl={async (uploadId) => {
const res = await fetch(`/api/upload/${uploadId}/preview-url`);
const { url } = await res.json();
return url;
}}
validatorMapper={{
emailUnico: async (value) => {
const existe = await api.verificarEmail(String(value));
return existe ? "E-mail já cadastrado" : undefined;
},
}}
onSubmitStep={async (step, values) => api.salvarRascunho(step, values)}
onComplete={async (values) => api.finalizar(values)}
onValuesChange={(values) =>
sessionStorage.setItem("rascunho", JSON.stringify(values))
}
/>;

StepIndicator customizado

Substitua o indicador de step built-in com seu próprio componente:

import type { StepIndicatorProps } from "@schema-forms-data/renderer";

function MeuStepIndicator({
steps,
currentStep,
onStepClick,
}: StepIndicatorProps) {
return (
<div className="meus-steps">
{steps.map((step, i) => (
<button
key={step.id}
className={
i === currentStep ? "ativo" : i < currentStep ? "concluido" : ""
}
onClick={() => i < currentStep && onStepClick?.(i)}
>
{step.label}
</button>
))}
</div>
);
}

<FormRenderer
schema={schema}
StepIndicator={MeuStepIndicator}
onComplete={handleComplete}
/>;
interface StepIndicatorProps {
steps: Array<{ id: string; label?: string; icone?: string }>;
currentStep: number;
onStepClick?: (index: number) => void;
}