Skip to content

feat: Add dynamic uiSchema support for array items #4675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ec120e4
feat(ArrayField): add dynamic uiSchema function support
chathuraa Jun 14, 2025
7070127
feat(ArrayField): implement dynamic uiSchema.items function support
chathuraa Jun 14, 2025
b064129
fix: improve error messages for dynamic uiSchema functions
chathuraa Jun 14, 2025
e21fab9
fix(ArrayField): allow undefined UI schema for array items
chathuraa Jun 14, 2025
6da9a53
fix: preserve undefined values in uiSchema handling
chathuraa Jun 14, 2025
4c45993
fix: add id to Fieldset component in ArrayFieldTemplate
chathuraa Jun 14, 2025
0000a02
docs: enhance dynamic uiSchema documentation with examples and best p…
chathuraa Jun 21, 2025
cc646d8
Merge remote-tracking branch 'origin/main' into feat/dynamic-uischema…
chathuraa Jun 21, 2025
c880f1f
fix: replace nanoid with lodash/uniqueId and handle null uiSchema
chathuraa Jul 10, 2025
873059b
fix: correct CheckboxWidget event handlers and enhance getUiOptions
chathuraa Jul 10, 2025
80e0206
refactor(ArrayField): extract UI schema computation logic and fix che…
chathuraa Jul 11, 2025
fea1569
fix: pass checkbox state in onFocus and onBlur callbacks
chathuraa Jul 11, 2025
0c877a2
Merge branch 'main' into feat/dynamic-uischema-array-items
chathuraa Jul 11, 2025
6fd9469
Merge remote-tracking branch 'fork/feat/dynamic-uischema-array-items'…
chathuraa Jul 11, 2025
96bdcf4
Merge branch 'main' into feat/dynamic-uischema-array-items
chathuraa Jul 25, 2025
5280e5a
Merge remote-tracking branch 'origin/main' into feat/dynamic-uischema…
chathuraa Aug 2, 2025
bfe373d
fix: ensure validator passed in Form rerenders & prevent null schema …
chathuraa Aug 2, 2025
32ff5b0
fix: use current value instead of event target in checkbox onFocus/on…
chathuraa Aug 11, 2025
2ebf860
Merge branch 'main' into feat/dynamic-uischema-array-items
chathuraa Aug 11, 2025
a5760f6
Merge branch 'main' into feat/dynamic-uischema-array-items
chathuraa Aug 12, 2025
41c079b
docs: updated the docs - added support for dynamic UI schema in array…
chathuraa Aug 12, 2025
1c4ac14
Merge remote-tracking branch 'fork/feat/dynamic-uischema-array-items'…
chathuraa Aug 12, 2025
7d08762
Merge branch 'main' into feat/dynamic-uischema-array-items
chathuraa Aug 12, 2025
051a7f5
docs(migration): add documentation for dynamic UI schema for array items
chathuraa Aug 12, 2025
2826971
Merge remote-tracking branch 'fork/feat/dynamic-uischema-array-items'…
chathuraa Aug 12, 2025
8f57e97
Update CHANGELOG.md
chathuraa Aug 12, 2025
9563af5
Update packages/docs/docs/migration-guides/v6.x upgrade guide.md
chathuraa Aug 12, 2025
1300100
Update packages/docs/docs/migration-guides/v6.x upgrade guide.md
chathuraa Aug 12, 2025
d10c54c
Update packages/docs/docs/json-schema/arrays.md
chathuraa Aug 12, 2025
b8a385a
Update packages/docs/docs/api-reference/dynamic-ui-schema-examples.md
chathuraa Aug 12, 2025
3a4bc80
Update packages/docs/docs/api-reference/dynamic-ui-schema-examples.md
chathuraa Aug 12, 2025
b068a2c
Update packages/docs/docs/api-reference/uiSchema.md
chathuraa Aug 12, 2025
4e96ecc
Update packages/docs/docs/api-reference/dynamic-ui-schema-examples.md
chathuraa Aug 12, 2025
0d4a931
docs: added about correcting checkbox widget focus handlers across al…
chathuraa Aug 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,47 @@ it according to semantic versioning. For example, if your PR adds a breaking cha
should change the heading of the (upcoming) version to include a major version bump.

-->

# 6.0.0-beta.14

## @rjsf/core

- Added support for dynamic UI schema in array fields - the `items` property in `uiSchema` can now accept a function that returns a UI schema based on the array item's data, index, and form context ([#4706](https://github.com/rjsf-team/react-jsonschema-form/pull/4706))
- Fixed checkbox widget to use current value instead of event target in onFocus/onBlur handlers, fixing [#4704](https://github.com/rjsf-team/react-jsonschema-form/issues/4704)

## @rjsf/utils

- Updated `UiSchema` type to support dynamic array item UI schemas - the `items` property can now be either a `UiSchema` object or a function that returns a `UiSchema` ([#4706](https://github.com/rjsf-team/react-jsonschema-form/pull/4706))

## @rjsf/chakra-ui

- Fixed checkbox widget to use current value instead of event target in onFocus/onBlur handlers, fixing [#4704](https://github.com/rjsf-team/react-jsonschema-form/issues/4704)

## @rjsf/daisyui

- Fixed checkbox widget to use current value instead of event target in onFocus/onBlur handlers, fixing [#4704](https://github.com/rjsf-team/react-jsonschema-form/issues/4704)

## @rjsf/fluentui-rc

- Fixed checkbox widget to use current value instead of event target in onFocus/onBlur handlers, fixing [#4704](https://github.com/rjsf-team/react-jsonschema-form/issues/4704)

## @rjsf/mui

- Fixed checkbox widget to use current value instead of event target in onFocus/onBlur handlers, fixing [#4704](https://github.com/rjsf-team/react-jsonschema-form/issues/4704)

## @rjsf/primereact

- Fixed checkbox widget to use current value instead of event target in onFocus/onBlur handlers, fixing [#4704](https://github.com/rjsf-team/react-jsonschema-form/issues/4704)

## @rjsf/semantic-ui

- Fixed checkbox widget to use current value instead of event target in onFocus/onBlur handlers, fixing [#4704](https://github.com/rjsf-team/react-jsonschema-form/issues/4704)

## Dev / docs / playground

- Added comprehensive documentation for dynamic UI schema feature with TypeScript examples ([#4706](https://github.com/rjsf-team/react-jsonschema-form/pull/4706))
- Updated array documentation to reference the new dynamic UI schema capabilities ([#4706](https://github.com/rjsf-team/react-jsonschema-form/pull/4706))

# 6.0.0-beta.13

## @rjsf/shadcn
Expand Down
4 changes: 2 additions & 2 deletions packages/chakra-ui/src/CheckboxWidget/CheckboxWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export default function CheckboxWidget<
const description = options.description || schema.description;

const _onChange = ({ checked }: CheckboxCheckedChangeDetails) => onChange(checked);
const _onBlur = ({ target }: FocusEvent<HTMLInputElement | any>) => onBlur(id, target && target.value);
const _onFocus = ({ target }: FocusEvent<HTMLInputElement | any>) => onFocus(id, target && target.value);
const _onBlur = ({ target }: FocusEvent<HTMLInputElement | any>) => onBlur(id, target && target.checked);
const _onFocus = ({ target }: FocusEvent<HTMLInputElement | any>) => onFocus(id, target && target.checked);

const chakraProps = getChakra({ uiSchema });

Expand Down
64 changes: 55 additions & 9 deletions packages/core/src/components/fields/ArrayField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import cloneDeep from 'lodash/cloneDeep';
import get from 'lodash/get';
import isObject from 'lodash/isObject';
import set from 'lodash/set';
import { nanoid } from 'nanoid';
import uniqueId from 'lodash/uniqueId';

/** Type used to represent the keyed form data used in the state */
type KeyedFormDataType<T> = { key: string; item: T };
Expand All @@ -37,7 +37,7 @@ type ArrayFieldState<T> = {

/** Used to generate a unique ID for an element in a row */
function generateRowId() {
return nanoid();
return uniqueId('rjsf-array-item-');
}

/** Converts the `formData` into `KeyedFormDataType` data, using the `generateRowId()` function to create the key
Expand Down Expand Up @@ -423,6 +423,39 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
onChange(value, undefined, idSchema && idSchema.$id);
};

/** Helper method to compute item UI schema for both normal and fixed arrays
* Handles both static object and dynamic function cases
*
* @param uiSchema - The parent UI schema containing items definition
* @param item - The item data
* @param index - The index of the item
* @param formContext - The form context
* @returns The computed UI schema for the item
*/
private computeItemUiSchema(
uiSchema: UiSchema<T[], S, F>,
item: T,
index: number,
formContext: F,
): UiSchema<T[], S, F> | undefined {
if (typeof uiSchema.items === 'function') {
try {
// Call the function with item data, index, and form context
// TypeScript now correctly infers the types thanks to the ArrayElement type in UiSchema
const result = uiSchema.items(item, index, formContext);
// Only use the result if it's truthy
return result as UiSchema<T[], S, F>;
} catch (e) {
console.error(`Error executing dynamic uiSchema.items function for item at index ${index}:`, e);
// Fall back to undefined to allow the field to still render
return undefined;
}
} else {
// Static object case - preserve undefined to maintain backward compatibility
return uiSchema.items as UiSchema<T[], S, F> | undefined;
}
}

/** Renders the `ArrayField` depending on the specific needs of the schema and uischema elements
*/
render() {
Expand Down Expand Up @@ -500,6 +533,10 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
const itemErrorSchema = errorSchema ? (errorSchema[index] as ErrorSchema<T[]>) : undefined;
const itemIdPrefix = idSchema.$id + idSeparator + index;
const itemIdSchema = schemaUtils.toIdSchema(itemSchema, itemIdPrefix, itemCast, idPrefix, idSeparator);

// Compute the item UI schema using the helper method
const itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);

return this.renderArrayFieldItem({
key,
index,
Expand All @@ -512,7 +549,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
itemIdSchema,
itemErrorSchema,
itemData: itemCast,
itemUiSchema: uiSchema.items,
itemUiSchema,
autofocus: autofocus && index === 0,
onBlur,
onFocus,
Expand Down Expand Up @@ -751,11 +788,20 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
: itemSchemas[index]) || {};
const itemIdPrefix = idSchema.$id + idSeparator + index;
const itemIdSchema = schemaUtils.toIdSchema(itemSchema, itemIdPrefix, itemCast, idPrefix, idSeparator);
const itemUiSchema = additional
? uiSchema.additionalItems || {}
: Array.isArray(uiSchema.items)
? uiSchema.items[index]
: uiSchema.items || {};
// Compute the item UI schema - handle both static and dynamic cases
let itemUiSchema: UiSchema<T[], S, F> | undefined;
if (additional) {
// For additional items, use additionalItems uiSchema
itemUiSchema = uiSchema.additionalItems as UiSchema<T[], S, F>;
} else {
// For fixed items, uiSchema.items can be an array, a function, or a single object
if (Array.isArray(uiSchema.items)) {
itemUiSchema = uiSchema.items[index] as UiSchema<T[], S, F>;
} else {
// Use the helper method for function or static object cases
itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);
}
}
const itemErrorSchema = errorSchema ? (errorSchema[index] as ErrorSchema<T[]>) : undefined;

return this.renderArrayFieldItem({
Expand Down Expand Up @@ -811,7 +857,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
canMoveDown: boolean;
itemSchema: S;
itemData: T[];
itemUiSchema: UiSchema<T[], S, F>;
itemUiSchema: UiSchema<T[], S, F> | undefined;
itemIdSchema: IdSchema<T[]>;
itemErrorSchema?: ErrorSchema<T[]>;
autofocus?: boolean;
Expand Down
Loading