Skip to content
Playground Form Builder

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,
type Validator,
} from "@/core/index.js";
import type { FormInternalContext } from "../context/index.js";
import type { ResolveFieldType } from "../fields.js";
export function resolver<V extends Validator>(
_: FormInternalContext<V>
): ResolveFieldType {
return ({ schema }) => {
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 scheme:

const schema: Schema = {
enum: ["foo", "bar", "baz"]
}

For this scheme, 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 in the UI scheme the field:

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 scheme 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,
type Validator,
} from "@/core/index.js";
import {
type FormInternalContext,
isFilesArray,
isMultiSelect,
isSelect,
retrieveUiOption,
} from "../context/index.js";
import type { ResolveFieldType } from "../fields.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<V extends Validator>(
ctx: FormInternalContext<V>
): ResolveFieldType {
return (config) => {
const { schema } = config;
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`;
};
}