Skip to content
EspañolEnglish
All components (244)

Form from a schema

Fields · SchemaForm

What it is and when to use it

A whole form built from a JSON Schema: the fields, their labels and their rules come from the schema, and it is validated with that same schema (the one the server already uses). Inside it is a Form: focus goes to the first invalid field, the error summary is announced and it is not submitted twice.

When to use it

  • When a configuration, a backend or an AI describes the form and you do not want to write each field by hand.
  • For forms with conditions (if/then/else, dependentRequired, oneOf by a fixed value): fields appear and go away according to what is typed, and what is switched off does not travel on submit.
  • For lists that grow (a list of objects) and nested objects, and for long forms through steps.

When not to

  • A small fixed form: Form with its connected fields gives more control over the layout.
  • A wizard whose steps are not fields of one schema: Wizard.

Which field comes from which schema: text, email (format: email), web (uri), password (writeOnly), text area (x-multiline or a long maxLength), number (with minimum, maximum and multipleOf as the step), switch (boolean), radio buttons (an enum of up to four options) or a dropdown (more), multiple selector (a list of enum), date, time and date with time (format date, time, date-time). ui changes the field, the label, the hint, the order or hides it, by the dotted path of the field (in a list, lines.*.sku).

Keyboard and accessibility: the fields are the usual ones, each with its label linked; what is required is announced as such, an object is a fieldset with its legend and each error appears next to its field and in the summary. In steps, you do not move on until the step's fields are valid and the new step is announced.

Validation: no dependencies. It supports types, enum/const, length, pattern and formats of a text, limits and multiples of a number, size and repeats of a list, allOf/anyOf/oneOf/not, conditions and local references (#/$defs/...). An empty field counts as absent. The error texts come out in the active language.

What it looks like

Plan

Fill it in and send it: what the server would receive shows up here.

const esquema: JsonSchema = {
  type: "object",
  properties: {
    nombre: { type: "string", title: "Name", minLength: 2 },
    correo: { type: "string", title: "Email", format: "email" },
    plan: { type: "string", title: "Plan", enum: ["Basic", "Professional"] },
    avisos: { type: "boolean", title: "Get email notifications" },
  },
  required: ["nombre", "correo"],
};

<SchemaForm label="Customer registration" schema={esquema} submitLabel="Register" onSubmit={guardar} />

Props

Import it with import { SchemaForm } from '@amset/ui/form'. Required props are marked.

PropTypeWhat it does
schemarequiredJsonSchemaEl esquema del formulario: un objeto, descrito con JSON Schema. Los mismos que valida el servidor.
uiUiSchemaLo que se puede decir de cada campo aparte de su esquema, por su ruta con puntos.
initialValuesReadonly<Record<string, unknown>>Valores con los que empieza, por encima de los `default` del esquema. Si cambian despues (datos que llegan de una peticion), el formulario los toma sin pisar lo que la persona ya haya cambiado a mano.
onSubmitrequiredFormProps<Record<string, unknown>>['onSubmit']Se llama solo con los datos ya validados y limpios: sin campos vacios y sin los que una condicion ha apagado. Lo que devuelve se pinta como en `Form`: `errors` en sus campos y `error` en el resumen.
stepsreadonly SchemaFormStep[]Parte el formulario en pasos: cada uno pide sus campos y no deja avanzar hasta que valen.
labelstringEl nombre del formulario, para el lector de pantalla. Por defecto, el `title` del esquema.
submitLabelstringEl texto del boton de enviar (o de terminar, en pasos).
summaryboolean—
validateOnFormProps<Record<string, unknown>>['validateOn']—
widgetsReadonly<Record<string, SchemaWidgetRenderer>>Widgets propios, por nombre: `widgets={{ swatch: (field) => <Swatch {...field} /> }}` y `ui={{ color: { widget: 'swatch' } }}`. El widget recibe su valor, su error y los datos de todo el formulario.
onChange(values: Readonly<Record<string, unknown>>, state: { readonly dirty: boolean; }) => voidSe llama en cada cambio de los datos (no al montar), con los datos tal cual estan en el formulario y si ha cambiado respecto a lo ultimo guardado (`dirty`): sirve para avisar antes de salir con cambios sin guardar. Un envio que sale bien cuenta como guardado y vuelve a `dirty: false`.
classNamestring—

In the test bench

Every state and variant, to try one at a time, on its page at ui.amset.tech: