For AI agents: the complete documentation index is available at https://a3s-lab.github.io/UI/v0.4.1/en/llms.txt, the full documentation bundle is available at https://a3s-lab.github.io/UI/v0.4.1/en/llms-full.txt, and this page is available as Markdown at https://a3s-lab.github.io/UI/v0.4.1/en/components/form-system/matrix-fields.md.

Matrix fields

Matrix fields let multiple question rows share one option set. They work well for assessment scales, capability coverage, permission combinations, and bulk parameter selection. Field values are always plain JSON objects with no component state or runtime identity.

  • matrix-single: select one option per row.
  • matrix-multiple: select multiple options per row.

Rows and columns are declared in the UI node's matrix property, while JSON Schema declares value types and selection limits. The compiler checks both sides and refuses to produce a FormPlan when they disagree.

Single-choice matrix matrix-single

Each row value in a single-choice matrix is a JSON primitive. Radios in the same row share a native name: Tab enters the option group, and the arrow keys move to and select an answer.

实时示例Record<string, JsonPrimitive>
协作体验评估

每行选择一个最符合实际情况的答案。

待改进基本可用符合预期表现出色
成员与 Agent 的任务交接是否清晰必选
执行结果是否容易追溯必选包含输入、输出和失败原因。
异常恢复是否符合预期必选
受控值
{
  "assessment": {
    "coordination": "expected",
    "traceability": "usable",
    "recovery": "expected"
  }
}
ItemConfiguration
Value typeRecord<string, JsonPrimitive>
Row valueOne stable column value per row
SchemaObject properties keyed by row ID, each using column values as its enum
UI propertiesmatrix.rows, matrix.columns

Controlled value shape:

type SingleMatrixValue = Record<string, string | number | boolean>;

Example value:

{
  "assessment": {
    "coordination": "expected",
    "traceability": "usable",
    "recovery": "expected"
  }
}

Multiple-choice matrix matrix-multiple

Each row value in a multiple-choice matrix is an array of primitives. minItems, maxItems, and uniqueItems control the minimum selection count, maximum selection count, and deduplication respectively.

实时示例Record<string, JsonPrimitive[]>
各环节具备哪些特征

每行选择一至两项。

待改进基本可用符合预期表现出色
成员与 Agent 的任务交接是否清晰必选已选择 2 项 · 最多 2 项
执行结果是否容易追溯必选包含输入、输出和失败原因。已选择 1 项 · 最多 2 项
异常恢复是否符合预期必选已选择 1 项 · 最多 2 项
受控值
{
  "assessment": {
    "coordination": [
      "usable",
      "expected"
    ],
    "traceability": [
      "expected"
    ],
    "recovery": [
      "usable"
    ]
  }
}
ItemConfiguration
Value typeRecord<string, JsonPrimitive[]>
Row valueA set of stable column values per row
SchemaEach row property uses an array Schema with column values as its enum
LimitsRow Schema minItems, maxItems, and uniqueItems

Once a row reaches maxItems, its unselected options are disabled while selected options can still be cleared. The limit applies only to that row and does not affect other rows.

type MultipleMatrixValue = Record<string, Array<string | number | boolean>>;

UI node properties

Matrix fields use the shared field properties and add a strongly typed matrix configuration.

PropertyTypeRequiredDescription
idstringYesNode identifier unique within the document
kind"field"YesMatrices always use a field node
widget"matrix-single" | "matrix-multiple"YesSelects the single- or multiple-choice value contract
schemaPathJSON PointerYesPoints to the matrix object Schema
labelstringNoVisible title, table name, and accessible name
descriptionstringNoInstructions for completing the matrix
matrixUiMatrixDefinitionYesStable row and column configuration
readOnlybooleanNoDisables every control in the matrix
width1–12NoWidth in the 12-column layout

UiMatrixDefinition:

interface UiMatrixDefinition {
  rows: UiMatrixRow[];
  columns: UiMatrixColumn[];
}

interface UiMatrixRow {
  id: string;
  label: string;
  description?: string;
  disabled?: boolean;
}

interface UiMatrixColumn {
  label: string;
  value: string | number | boolean;
  disabled?: boolean;
}

Row properties

PropertyPurpose
idUsed both as the controlled-value key and the matrix child-Schema property name; keep it stable after publication
labelDesktop row heading, narrow-container card title, and part of each control's accessible name
descriptionSupporting text below the row heading, associated with options through aria-describedby
disabledDisables the whole row while retaining its controlled value

A row id cannot be empty, contain ., or use the reserved value *. Row IDs must be unique within a matrix.

Column properties

PropertyPurpose
labelDesktop column heading and option title in narrow containers
valueStable primitive written to the controlled value when selected
disabledDisables this column's control in every row

All column values in one matrix must be string, all number, or all boolean. null is not a column value; an absent row property represents the unselected state. Column values must be unique.

Single-choice matrix Schema

The matrix itself binds to an object Schema. Each matrix.rows[].id has a matching properties entry whose enum exactly matches the column values.

const document: FormDocument = {
  kind: 'a3s.form',
  apiVersion: 'a3s.dev/form/v1alpha1',
  revision: 1,
  metadata: { title: 'Collaboration experience', locale: 'en-US' },
  schema: {
    $schema: 'https://json-schema.org/draft/2020-12/schema',
    type: 'object',
    properties: {
      assessment: {
        type: 'object',
        properties: {
          coordination: {
            type: 'string',
            enum: ['low', 'expected', 'excellent'],
          },
          traceability: {
            type: 'string',
            enum: ['low', 'expected', 'excellent'],
          },
        },
        required: ['coordination', 'traceability'],
        additionalProperties: false,
      },
    },
    required: ['assessment'],
    additionalProperties: false,
  },
  ui: {
    root: 'root',
    nodes: [
      { id: 'root', kind: 'root', children: ['assessment'] },
      {
        id: 'assessment',
        kind: 'field',
        widget: 'matrix-single',
        label: 'Collaboration experience assessment',
        schemaPath: '/properties/assessment',
        matrix: {
          rows: [
            { id: 'coordination', label: 'Task handoffs are clear' },
            { id: 'traceability', label: 'Execution results are traceable' },
          ],
          columns: [
            { label: 'Needs improvement', value: 'low' },
            { label: 'Meets expectations', value: 'expected' },
            { label: 'Excellent', value: 'excellent' },
          ],
        },
      },
    ],
  },
};

The object Schema must set additionalProperties: false. Its properties cannot omit declared rows or retain orphaned properties that do not appear in matrix.rows.

Multiple-choice matrix Schema

Multiple-choice rows use array Schemas. items.enum matches the column values, and uniqueItems must be true.

{
  "type": "object",
  "properties": {
    "coordination": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": ["low", "expected", "excellent"]
      },
      "minItems": 1,
      "maxItems": 2,
      "uniqueItems": true
    }
  },
  "required": ["coordination"],
  "additionalProperties": false
}

minItems and maxItems cannot exceed the column count. The parent matrix Schema's required determines which rows must appear in the object. Multiple-choice rows usually also set minItems: 1 so an empty array cannot pass required validation.

Designer configuration

The component catalog provides “Single-choice matrix” and “Multiple-choice matrix” presets. A preset writes the UI node, object Schema, row Schemas, and column values together.

The properties panel supports:

  • Editing row and column labels individually while showing stable row id and column value values.
  • Adding, removing, reordering, disabling, and re-enabling rows and columns.
  • Updating labels by row in a collapsible bulk editor.
  • Switching between single- and multiple-choice matrices while replacing row Schemas in sync.
  • Preserving existing row IDs and column values so label edits do not rewrite saved form values.

The structured editor stays synchronized with the object Schema: reordering rows rebuilds properties in the same order, removing a row removes its property and required entry, and reordering columns updates every row's enum. Disabling a row or column changes only UI availability; it does not remove Schema values or existing controlled values.

New rows receive unused stable IDs and copy the current row-Schema shape. New columns keep the existing column-value type. Add buttons become disabled at the compiler limits for row count, column count, or total cell count.

The validation panel supports:

  • Making the whole matrix required.
  • Making individual rows required.
  • Setting each row's minItems and maxItems in a multiple-choice matrix.

The design canvas shows the row and column structure directly. Interactive preview uses the real FormRenderer and returns selections as the complete controlled object.

Keyboard and screen readers

ActionSingle-choice matrixMultiple-choice matrix
Tab / Shift+TabMove between each row's radio groupMove through checkboxes in order
Arrow keysMove between and select radio options in the current rowDo not change selection
SpaceSelect the current radioToggle the current checkbox
Home / EndUse native browser radio-group behaviorDo not change selection

The runtime uses a semantic table, column headings, and row headings with scope="row". Each control's accessible name combines “row label: column label.” Row descriptions, selection counts, limits, and errors are associated through aria-describedby.

At container widths of 520px or less, the matrix becomes a card layout by row. Column labels appear beside each option while the DOM retains table semantics. Responsive behavior reads the embedding container's width rather than the browser viewport.

States and limits

StateBehavior
UnselectedA single-choice row omits the property; the host decides whether a multiple-choice row is omitted or passed as an empty array
Required errorThe error binds to matrix path.row identifier; the row displays it and participates in first-error focus
Disabled rowEvery control in the row is disabled without deleting existing values
Disabled columnThat column is disabled in every row
Limit reachedUnselected options are disabled; selected options can still be cleared
Read-only formAll matrix controls are disabled while content remains readable
Long labelsLabels wrap; narrow containers use row cards to avoid horizontal text compression

Compiler limits:

ItemLimit
Rows50
Columns20
Total cells500

Documents beyond these limits receive a matrix.limits diagnostic. Larger two-dimensional datasets should use paginated editing, a virtualized grid, or a dedicated host component.

Embedding boundary

Matrix values contain no submission records, authorization data, network addresses, or internal component state. An embedded host needs only a plain object connected to controlled state through value and onChange.

<FormRenderer
  plan={plan}
  value={nodeConfiguration}
  onChange={setNodeConfiguration}
  readOnly={!canEdit}
/>

Dynamic columns, remote options, and cell-level business components are outside the built-in matrix contract. Implement them with reviewed custom nodes, while credentials, requests, and side effects remain under host control.