Skip to content
Playground

Reusable defaults

Even with a simple setup, resulting code is very verbose. Therefore, it is convenient to create a file with a re-export of the selected resolver, theme, validator and translation.

form-defaults.ts
export { resolver } from "@sjsf/form/resolvers/compat";
import "@sjsf/form/fields/extra-fields/enum-include";
import "@sjsf/form/fields/extra-fields/file-include";
export { theme } from "@sjsf/basic-theme";
import "@sjsf/basic-theme/extra-widgets/textarea-include";
import "@sjsf/basic-theme/extra-widgets/file-include";
export { translation } from "@sjsf/form/translations/en";
import { createFormValidator } from "@sjsf/ajv8-validator";
// NOTE: One validator will be used for all forms
export const validator = createFormValidator();

And use it like this

import * as defaults from '$lib/form-defaults'
const form = createForm({ ...defaults, ... })

You could go further and create a wrapper around the createForm.

my-form.ts
import { type FormOptions, type Validator, createForm } from "@sjsf/form";
import * as defaults from "./form-defaults";
type Defaults = keyof typeof defaults;
export type MyValidator = (typeof defaults)["validator"];
export type MyFormOptions<T, V extends Validator> = Omit<
FormOptions<T, V>,
Defaults
> &
Partial<Pick<FormOptions<T, V>, Defaults>>;
export function createMyForm<
T,
V extends Validator,
O extends MyFormOptions<T, V>
>(options: O) {
return createForm(
new Proxy(options, {
get(target, p, receiver) {
if (!(p in target)) {
return defaults[p as Defaults];
}
return Reflect.get(target, p, receiver);
},
}) as unknown as FormOptions<
T,
O extends { validator: V } ? V : MyValidator
>
);
}

You also can create your own form component.

my-form.svelte
<script
lang="ts"
generics="T, V extends Validator, O extends MyFormOptions<T, V>"
>
import { BasicForm, type Validator } from "@sjsf/form";
import { type MyFormOptions, createMyForm } from "./my-form";
const props: O = $props();
const form = createMyForm<T, V, O>(props);
</script>
<BasicForm {form} />