Skip to content
Playground

Manual mode

Manual mode gives you complete control over form layout and field placement.

<script lang="ts">
import {
type Schema,
createForm,
enhance,
Field,
} from "@sjsf/form";
import type { FromSchema } from "json-schema-to-ts";
import * as defaults from "@/components/form-defaults";
const schema = {
type: "object",
properties: {
login: {
title: "Login",
type: "string",
minLength: 3,
},
password: {
title: "Password",
type: "string",
minLength: 6,
},
},
required: ["login", "password"],
additionalProperties: false,
} as const satisfies Schema;
const form = createForm({
...defaults,
schema,
onSubmit(value: FromSchema<typeof schema>) {
console.log(value);
},
});
</script>
<form
novalidate
use:enhance={form.context}
style="display: flex; flex-direction: column; gap: 1rem;"
>
<Field {form} name="login" />
<Field
{form}
name="password"
uiSchema={{ "ui:options": { text: { type: "password" } } }}
/>
<button type="submit">Submit</button>
</form>

To make the field names inference work - it is necessary to define the type of form value, for example, like this:

const form = createForm<ValueType, typeof validator>(...)

You must initialize nested structures (objects and arrays). In the following example, if you want to display the foo.bar field, you should initialize the foo object through the initialValue option.

const schema = {
type: "object",
properties: {
foo: {
type: "object",
properties: {
bar: {
type: "string",
},
},
},
},
} as const satisfies Schema;
const initialValue = {
foo: {}
}

Calculating the value of the required property from the JSON schema can be tricky, if it is calculated incorrectly - specify it manually.

<Field {form} name="foo" required />

Unlike other form components (Form, SubmitButton, etc.), Field does not require setting the form context.