Skip to content
PlaygroundForm Builder

Install as a community add-on using the Svelte CLI.

Terminal window
npx sv add @sjsf

Required peer dependencies: esm-env@1.2.0 svelte@5.34.8

Let’s start with the simplest setup:

<script lang="ts">
  import { theme } from "@sjsf/basic-theme";
  import { SimpleForm } from "@sjsf/form";
  import { createFormIdBuilder } from "@sjsf/form/id-builders/modern";
  import { createFormMerger } from "@sjsf/form/mergers/modern";
  import { resolver } from "@sjsf/form/resolvers/basic";
  import { translation } from "@sjsf/form/translations/en";
  import { createFormValidator } from "@sjsf/form/validators/noop";
</script>

<SimpleForm
  {theme}
  {translation}
  {resolver}
  schema={{
    type: "object",
    title: "Form title",
    properties: {
      text: {
        type: "string",
        title: "Text input",
      },
    },
    required: ["text"],
  }}
  merger={createFormMerger}
  idBuilder={createFormIdBuilder}
  validator={createFormValidator<{ text: string }>}
  onSubmit={(v) => window.alert(v.text)}
/>

In the example above, we create a form based on JSON Schema and use HTML5 validation to validate the form.

Although this is an extremely simple example, it turned out to be quite verbose, and here’s why:

  • Explicit Configuration: The library favors explicit configuration over “magic” defaults.
  • Tree-Shakeable Architecture: Each feature is located in its own submodule so you can import only the functionality you need, keeping your bundle lean and optimized.
  • Highly Customizable: We provide extensive customization options so that you can tailor every aspect of the library to your needs.

With the uiSchema parameter you can customize the appearance of the form.

<script lang="ts">
  import { type Schema, type UiSchemaRoot, SimpleForm } from "@sjsf/form";

  import * as defaults from "$lib/sjsf/defaults";

  const schema: Schema = {
    type: "string",
  };

  const uiSchema: UiSchemaRoot = {
    "ui:options": {
      title: "Custom title",
      help: "Help text",
      text: {
        placeholder: "placeholder",
      },
    },
  };
</script>

<SimpleForm
  {...defaults}
  {schema}
  {uiSchema}
  onSubmit={(v) => window.alert(v)}
/>

Use a factory to create a form to access its state.

<script lang="ts">
  import {
    BasicForm,
    createForm,
    getErrors,
    getValueSnapshot,
    type Schema,
  } from "@sjsf/form";

  import * as defaults from "$lib/sjsf/defaults";

  const schema: Schema = {
    type: "string",
    minLength: 10,
  };

  const form = createForm({
    ...defaults,
    initialValue: "initial",
    schema,
    onSubmit: console.log,
  });
</script>

<BasicForm {form} novalidate />

<pre>{JSON.stringify(
    { value: getValueSnapshot(form), errors: Array.from(getErrors(form)) },
    null,
    2
  )}</pre>

You can also specify the value option instead of the initialValue to access the internal state of the form.

<script lang="ts">
  import { BasicForm, createForm, type Schema } from "@sjsf/form";

  import * as defaults from "$lib/sjsf/defaults";

  const schema: Schema = {
    type: "string",
  };

  let value = $state("initial");

  const form = createForm<string>({
    ...defaults,
    schema,
    value: [() => value, (v) => (value = v)],
    onSubmit: console.log,
  });
</script>

<BasicForm {form} />

<pre>{JSON.stringify(value, null, 2)}</pre>