mksingh
componentjsonforms-array-layoutsource: ok · hit
Jsonforms Array Layout
JSONForms accordion-based renderer for arrays of objects. Each item renders in a collapsible panel with add, remove, and reorder controls.
npx shadcn add "https://mksingh.dev/r/jsonforms-array-layout.json"free
Interaction
accordion
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · light@jsonforms/core@jsonforms/react
Registry dependencies
accordionbutton
Files1 · source cached 10/14/2026, 3:12:48 PM
registry/forms/renderers/array-layout.tsx
'use client';
import {
ArrayLayoutProps,
composePaths,
createDefaultValue,
findUISchema,
isObjectArrayWithNesting,
rankWith,
} from '@jsonforms/core';
import { JsonFormsDispatch, withJsonFormsArrayLayoutProps } from '@jsonforms/react';
import { useMemo } from 'react';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '~/components/ui/accordion';
import { Button } from '~/components/ui/button';
const ArrayLayoutRenderer = (props: ArrayLayoutProps) => {
const {
data,
path,
schema,
uischema,
uischemas,
renderers,
cells,
visible,
enabled,
label,
addItem,
removeItems,
moveUp,
moveDown,
rootSchema,
} = props;
const childUiSchema = useMemo(
() => findUISchema(uischemas ?? [], schema, uischema.scope, path, undefined, uischema, rootSchema),
[uischemas, schema, uischema, path, rootSchema]
);
if (!visible) return null;
return (
<div className="flex flex-col gap-3">
<div className="flex items-center justify-between">
{label && <label className="text-xs font-medium text-foreground">{label}</label>}
{enabled && (
<Button
type="button"
variant="outline"
size="sm"
onClick={() => addItem(path, createDefaultValue(schema, rootSchema))()}
className="text-xs"
>
+ Add
</Button>
)}
</div>
{data > 0 && (
<Accordion multiple>
{Array.from({ length: data }).map((_, index) => (
<AccordionItem key={index} value={String(index)}>
<AccordionTrigger>
<div className="flex items-center gap-2">
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-muted text-[10px] text-muted-foreground">
{index + 1}
</span>
<span className="text-xs">{label} {index + 1}</span>
</div>
</AccordionTrigger>
<AccordionContent>
<div className="flex flex-col gap-2 pt-1">
<JsonFormsDispatch
schema={schema}
uischema={childUiSchema}
path={composePaths(path, `${index}`)}
renderers={renderers}
cells={cells}
/>
{enabled && (
<div className="flex items-center gap-1 pt-1">
{moveUp && index > 0 && (
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => moveUp(path, index)()}
className="h-7 text-xs"
>
↑ Up
</Button>
)}
{moveDown && index < data - 1 && (
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => moveDown(path, index)()}
className="h-7 text-xs"
>
↓ Down
</Button>
)}
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => removeItems && removeItems(path, [index])()}
className="h-7 text-xs text-destructive hover:text-destructive"
>
Remove
</Button>
</div>
)}
</div>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
)}
</div>
);
};
export const arrayLayoutTester = rankWith(4, isObjectArrayWithNesting);
export default withJsonFormsArrayLayoutProps(ArrayLayoutRenderer);
More from mksingh
Jsonforms Anyof String Or Enum ControlcomponentJsonforms Boolean CellcomponentJsonforms Boolean ControlcomponentJsonforms Boolean Toggle CellcomponentJsonforms Boolean Toggle ControlcomponentJsonforms CategorizationcomponentJsonforms Controlcomponent
Browse all components in this library →