Component
JSON list input
<DomJsonListInput>A schema-aware editor for arrays of objects. Edit rows through form controls, or toggle to raw JSON for bulk changes.
Playground
Try every prop live
JSON list input playground
Use the fields mode for structured editing, then switch to JSON when copy, paste, or bulk edits are quicker.
Schema-aware rows with a raw JSON toggle.
<script setup>
import { reactive } from 'vue';
import { DomJsonListInput } from '@getdom/studio/vue';
const data = reactive({
"modelValue": [
{
"label": "Profile",
"value": "profile",
"shortcut": "Cmd+P"
},
{
"label": "Settings",
"value": "settings",
"shortcut": "Cmd+,"
}
],
"id": "",
"name": "",
"label": "Menu items",
"description": "Schema-aware rows with a raw JSON toggle.",
"placeholder": "",
"required": false,
"disabled": false,
"readOnly": false,
"invalid": false,
"errors": {},
"visible": true,
"validators": [],
"validateOnBlur": true,
"chrome": "field",
"addLabel": "+ Add item",
"schema": {
"type": "array",
"label": "Menu items",
"items": {
"type": "DomForm",
"properties": {
"label": {
"type": "string",
"label": "Label",
"placeholder": "Profile"
},
"value": {
"type": "string",
"label": "Value",
"placeholder": "profile"
},
"shortcut": {
"type": "string",
"label": "Shortcut",
"placeholder": "Cmd+P"
}
}
}
},
"jsonToggle": true,
"compact": false
});
</script>
<template>
<DomJsonListInput
v-bind="data"
@update:modelValue="data.modelValue = $event"
/>
</template>Demo
Label/value options
A label/value picker list is just DomJsonListInput with a two-field schema.
A simple label/value list is just a schema with two fields.
Bound elsewhere
[
{
"label": "Apple",
"value": "apple"
},
{
"label": "Banana",
"value": "banana"
},
{
"label": "Cherry",
"value": "cherry"
}
]<script setup>
import { ref } from 'vue';
import { DomDropdown, DomJsonListInput } from '../../../lib/vue';
const items = ref([
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Cherry', value: 'cherry' },
]);
const schema = {
type: 'array',
label: 'Dropdown items',
items: {
type: 'DomForm',
properties: {
label: {
type: 'string',
label: 'Label',
placeholder: 'Item label',
},
value: {
type: 'string',
label: 'Value',
placeholder: 'item-value',
},
},
},
};
</script>
<template>
<div class="grid w-full max-w-4xl gap-5 lg:grid-cols-[minmax(0,1fr)_18rem]">
<DomJsonListInput
v-model="items"
label="Dropdown items"
description="A simple label/value list is just a schema with two fields."
add-label="+ Add fruit"
:schema="schema"
/>
<div>
<p class="mb-2 text-xs font-medium uppercase tracking-wider text-muted-fg">Bound elsewhere</p>
<DomDropdown :items="items" label="Pick a fruit" />
<pre class="mt-3 overflow-auto rounded-xl border border-border bg-secondary/50 p-3 text-xs text-muted-fg">{{ items }}</pre>
</div>
</div>
</template>
Demo
Schema-driven rows
The standardized form schema controls which fields appear, their labels, placeholders, input types, options, and defaults for new rows.
Use the field editor for day-to-day edits, or switch to JSON for bulk changes.
[
{
"id": "toast-1",
"title": "Saved",
"tone": "success",
"duration": 3200
},
{
"id": "toast-2",
"title": "Could not publish",
"tone": "danger",
"duration": 0
}
]<script setup>
import { ref } from 'vue';
import { DomJsonListInput } from '../../../lib/vue';
const rows = ref([
{ id: 'toast-1', title: 'Saved', tone: 'success', duration: 3200 },
{ id: 'toast-2', title: 'Could not publish', tone: 'danger', duration: 0 },
]);
const schema = {
type: 'array',
label: 'Toast rows',
items: {
type: 'DomForm',
properties: {
id: {
type: 'string',
label: 'ID',
placeholder: 'toast-id',
},
title: {
type: 'string',
label: 'Title',
placeholder: 'Successfully saved',
},
tone: {
type: 'string',
component: 'DomSelectInput',
label: 'Tone',
options: [
'default',
'success',
'danger',
'warning',
],
},
duration: {
type: 'number',
label: 'Duration',
default: 3600,
},
},
},
};
</script>
<template>
<div class="grid w-full max-w-4xl gap-5 lg:grid-cols-[minmax(0,1fr)_18rem]">
<DomJsonListInput
v-model="rows"
label="Toast rows"
description="Use the field editor for day-to-day edits, or switch to JSON for bulk changes."
add-label="+ Add toast"
:schema="schema"
/>
<pre class="max-h-96 overflow-auto rounded-xl border border-border bg-secondary/50 p-3 text-xs text-muted-fg">{{ rows }}</pre>
</div>
</template>
Demo
Compact inspector mode
Compact mode keeps the editor useful inside a Studio-style inspector without removing the raw JSON toggle.
Meta
Compact mode is intended for inspectors and narrow panels.
<script setup>
import { ref } from 'vue';
import { DomJsonListInput } from '../../../lib/vue';
const people = ref([
{
value: 'person-1',
label: 'Maya Patel',
role: 'Product lead',
avatar: 'https://i.pravatar.cc/96?img=47',
meta: { team: 'Design systems', timezone: 'GMT' },
},
{
value: 'person-2',
label: 'Noah Hughes',
role: 'Frontend engineer',
avatar: 'https://i.pravatar.cc/96?img=12',
meta: { team: 'Studio', timezone: 'CET' },
},
]);
const schema = {
type: 'array',
label: 'People',
items: {
type: 'DomForm',
properties: {
value: {
type: 'string',
label: 'Value',
placeholder: 'person-id',
},
label: {
type: 'string',
label: 'Name',
placeholder: 'Person name',
},
role: {
type: 'string',
label: 'Role',
placeholder: 'Role or title',
},
avatar: {
type: 'url',
label: 'Avatar URL',
placeholder: 'https://...',
},
meta: {
type: 'DomForm',
label: 'Meta',
properties: {
team: {
type: 'string',
label: 'Team',
},
timezone: {
type: 'string',
label: 'Timezone',
},
},
},
},
},
};
</script>
<template>
<div class="w-full max-w-md rounded-2xl border border-border skin-raised p-4 text-fg">
<DomJsonListInput
v-model="people"
label="People"
description="Compact mode is intended for inspectors and narrow panels."
add-label="+ Add person"
:schema="schema"
compact
/>
</div>
</template>
Reference
Props
Control props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
modelValue | array | Array<unknown> | [] | — |
addLabel | string | string | '+ Add row' | Button label for adding a row. |
schema | array | object | Array<unknown> | — | Standardized form definition used by the visual editor. Legacy flat row schema arrays are still supported. |
jsonToggle | boolean | boolean | true | Show the visual/raw JSON mode switch. |
compact | boolean | boolean | false | Reduce vertical spacing for inspectors and narrow tool panels. |
Field props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
id | string | string | '' | Optional ID override. By default parent forms derive the input ID from the field path using underscores. |
name | string | string | '' | Local field name. Parent forms derive the full field path and native HTML name from the form hierarchy. |
label | string | string | '' | Visible field label. |
description | string | string | '' | Optional helper copy below the field. |
placeholder | string | string | '' | Placeholder shown when the control is empty. |
required | boolean | boolean | false | Mark the field as required. |
disabled | boolean | boolean | false | Disable field interaction. |
readOnly | boolean | boolean | false | Show the value but prevent editing. |
invalid | boolean | boolean | false | Mark the field invalid. |
errors | array | object | string | Array< | {} | Validation errors for this field. |
visible | boolean | boolean | true | Show or hide the field. |
validators | array | Array<unknown> | [] | Validators attached to this field. Use functions in Vue code, or serializable records such as { name: "minLength", props: { min: 2 } } in generated schemas. |
validateOnBlur | boolean | boolean | true | Run validators when the field loses focus. |
chrome | 'field' | false | string | 'field' | Render default field chrome, or false to render only the control while keeping form state wiring. |
Auto-generated from JSON list input.props and inline _edit hints.
Events
| Name | Payload | Description |
|---|---|---|
| @update:modelValue | Array<object> | Fired when rows are added, removed, reordered, edited, or replaced from valid raw JSON. |
| @focus | — | — |
| @blur | — | — |
Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.