@letar/forms

MatrixChoice

Matrix choice field for surveys, NPS forms, and questionnaires

Overview

Form.Field.MatrixChoice renders a "question x answer" matrix table — the standard pattern from Google Forms and SurveyMonkey. Supports three variants: radio (single choice), checkbox (multi choice), and rating (stars).

Basic Usage (Radio)

<Form initialValue={{ satisfaction: {} }} onSubmit={handleSubmit}>
  <Form.Field.MatrixChoice
    name="satisfaction"
    label="Rate our service"
    rows={[
      { value: 'speed', label: 'Delivery speed' },
      { value: 'quality', label: 'Product quality' },
      { value: 'support', label: 'Customer support' },
    ]}
    columns={[
      { value: '1', label: 'Terrible' },
      { value: '2', label: 'Bad' },
      { value: '3', label: 'OK' },
      { value: '4', label: 'Good' },
      { value: '5', label: 'Excellent' },
    ]}
    variant="radio"
  />
  <Form.Button.Submit>Submit</Form.Button.Submit>
</Form>

Value: { speed: '4', quality: '5', support: '3' }

Checkbox Variant (Multi-Select)

<Form.Field.MatrixChoice
  name="skills"
  variant="checkbox"
  rows={[
    { value: 'frontend', label: 'Frontend' },
    { value: 'backend', label: 'Backend' },
  ]}
  columns={[
    { value: 'beginner', label: 'Beginner' },
    { value: 'intermediate', label: 'Intermediate' },
    { value: 'expert', label: 'Expert' },
  ]}
/>

Value: { frontend: ['beginner', 'intermediate'], backend: ['expert'] }

Rating Variant

<Form.Field.MatrixChoice
  name="rating"
  variant="rating"
  rows={[
    { value: 'taste', label: 'Taste' },
    { value: 'presentation', label: 'Presentation' },
  ]}
  columns={[
    { value: '1', label: '1' },
    { value: '2', label: '2' },
    { value: '3', label: '3' },
    { value: '4', label: '4' },
    { value: '5', label: '5' },
  ]}
/>

Props

PropTypeDefaultDescription
namestringrequiredField name
labelstringLabel above matrix
rowsMatrixRow[]requiredQuestions (row labels)
columnsMatrixColumn[]requiredAnswer options (column headers)
variant'radio' | 'checkbox' | 'rating''radio'Selection mode
disabledbooleanfalseDisable all inputs
readOnlybooleanfalseRead-only mode

Keyboard Navigation

KeyAction
Arrow Right/LeftMove between columns
Arrow Up/DownMove between rows
Enter / SpaceSelect current cell

Required Validation

When required={true}, unfilled rows are highlighted in red after form validation triggers. Use Zod schema validation to enforce all rows are filled.

Responsive Behavior

On mobile (< md breakpoint), the table automatically switches to a card-based layout where each question is a separate card with vertically stacked options.


Live Example

Try the interactive example on forms-example.letar.best.

On this page