Fields resolution
To determine which field to use to display your JSON Schema,
the form uses resolver function.
Let’s take a look at the basic resolver implementation
(@sjsf/form/resolvers/basic):
import { getSimpleSchemaType, isFixedItems } from "@/core/index.js";
import type { ResolveFieldType } from "../fields.js";import { isCycleRef, type FormState } from "../state/index.js";
export function resolver<T>(ctx: FormState<T>): ResolveFieldType { return (config) => { const { schema } = config; if (isCycleRef(ctx, config)) { return "expandField"; } if (schema.oneOf !== undefined) { return "oneOfField"; } if (schema.anyOf !== undefined) { return "anyOfField"; } const type = getSimpleSchemaType(schema); if (type === "array") { return isFixedItems(schema) ? "tupleField" : "arrayField"; } return `${type}Field`; };}As you can see resolver just selects the field according to the schema type.
This approach is simple and straightforward, but in some cases it can lead to additional work. Suppose you have the following schema:
const schema: Schema = { enum: ["foo", "bar", "baz"],};For this schema, the basic resolver will select stringField,
and stringField will display the textWidget widget by default
although you probably wanted to see select or radio widgets.
To achieve this you need to specify the field in the UI schema:
const uiSchema: UiSchema = { "ui:components": { // The `selectWidget` will now be displayed by default stringField: "enumField", // You can also replace `selectWidget` with `radioWidget` // selectWidget: "radioWidget" },};Or you can modify resolver so that enumField is always used
when a schema with enum is detected:
return ({ schema }) => { if (schema.enum !== undefined) { return "enumField" } ...}It is recommended that you copy the basic resolver code into your project and
modify it to suit your needs.
As an example (or temporary solution) you can use the compat resolver
(@sjsf/form/resolvers/compat) that reproduces resolution logic from v1:
import { getSimpleSchemaType, isFileSchema, isFixedItems,} from "@/core/index.js";
import type { ResolveFieldType } from "../fields.js";import { isCycleRef, isFilesArray, isMultiSelect, isSelect, retrieveUiOption, type FormState,} from "../state/index.js";import "../extra-fields/enum.js";import "../extra-fields/multi-enum.js";import "../extra-fields/file.js";import "../extra-fields/files.js";
export function resolver<T>(ctx: FormState<T>): ResolveFieldType { return (config) => { const { schema } = config; if (isCycleRef(ctx, config)) { return "expandField"; } if (isSelect(ctx, schema)) { return "enumField"; } if (schema.oneOf !== undefined) { return "oneOfField"; } if (schema.anyOf !== undefined) { return "anyOfField"; } const type = getSimpleSchemaType(schema); if (type === "array") { if (isMultiSelect(ctx, schema)) { return "multiEnumField"; } if (isFixedItems(schema)) { return "tupleField"; } if ( isFilesArray(ctx, schema) && retrieveUiOption(ctx, config, "orderable") !== true ) { return "filesField"; } return "arrayField"; } if (isFileSchema(schema)) { return "fileField"; } return `${type}Field`; };}Some interchangeable components (tagsField, filesField, etc.) cannot be assigned directly
in the UI schema due to type incompatibilities.