Component casting
SJSF provides a rich set of interchangeable components,
but some of them cannot be used directly out of the box
(tagsField
, filesField
, nativeFileField
, etc.).
Let’s look at a few ways to work with them.
Ignore errors (not recommended)
Section titled “Ignore errors (not recommended)”You can suppress typing errors if you just want to quickly test an idea or see how a component looks in place.
const uiSchema: UiSchema = { "ui:components": { // @ts-expect-error arrayField: "tagsField" }}
Create an adapter component
Section titled “Create an adapter component”You can create a new component that adapts the interface of the original component
(for example, arrayField
) to the interface of the replacement component (tagsField
).
<script lang="ts" module> import type { SchemaArrayValue } from '@sjsf/form/core'; import type { FieldCommonProps } from '@sjsf/form';
declare module '@sjsf/form' { interface ComponentProps { anyTagsField: FieldCommonProps<SchemaArrayValue>; } interface ComponentBindings { anyTagsField: 'value'; } }</script>
<script lang="ts"> import type { ComponentProps } from '@sjsf/form'; import TagsField from '@sjsf/form/fields/extra-fields/tags.svelte';
import { assertStrings } from '$lib/form/cast';
let { value = $bindable(), ...rest }: ComponentProps['arrayField'] = $props();</script>
<TagsField {...rest} bind:value={ () => { assertStrings(value); return value; }, (v) => (value = v) }/>
Why is this needed? Throwing an error when data formats don’t match is only one possible approach. You should decide on the adaptation strategy and implement it yourself for now, but in the future the library may provide ready-made adapted components.
You can reduce boilerplate code by using the cast
utility from @sjsf/form/lib/component
:
import { cast } from "@sjsf/form/lib/component";import type { ComponentDefinition } from "@sjsf/form";import TagsField from "@sjsf/form/fields/extra-fields/tags.svelte";
import { assertStrings } from '$lib/form/cast';
declare module "@sjsf/form" { interface ComponentProps { tagsFieldWrapper: FieldCommonProps<SchemaArrayValue>; } interface ComponentBinding { tagsFieldWrapper: "value"; }}
const tagsFieldWrapper = cast(TagsField, { value: { transform(props) { assertStrings(props.value); return props.value; }, },}) satisfies ComponentDefinition<"arrayField">;
Extend the resolver
Section titled “Extend the resolver”Instead of proving component compatibility at the type level, you can extend the resolver so that components are applied automatically to suitable JSON Schemas.