npm package: @question-forms/react
Description: React Web renderer for Question Forms SDK
Author: question-forms
Latest version: 0.5.4

# @question-forms/react

React Web renderer for the [Question Forms SDK](https://jolly-dune-009ebe90f.4.azurestaticapps.net/) — render schema-driven forms with Material UI, build forms visually, and customize everything.

## Installation

```bash
npm install @question-forms/core @question-forms/react
```

### Peer Dependencies

```bash
npm install react react-dom @mui/material @mui/icons-material @mui/x-date-pickers \
  @emotion/react @emotion/styled dayjs \
  @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
```

## Quick Start

```tsx
import { useState } from 'react';
import { QuestionForm } from '@question-forms/react';
import type { FormSchema, FormValues } from '@question-forms/core';

const schema: FormSchema = {
    id: 'my-form',
    sections: [
        {
            id: 'section-1',
            questions: [
                {
                    id: 'q1',
                    key: 'name',
                    type: 'TEXT',
                    subtype: 'short',
                    label: 'Your Name',
                    required: true,
                },
            ],
        },
    ],
};

function MyForm() {
    const [values, setValues] = useState<FormValues>({});

    return (
        <QuestionForm
            schema={schema}
            value={values}
            onChange={setValues}
            onSubmit={(v) => console.log('Submitted:', v)}
        />
    );
}
```

## Features

- **10 question types** — text, date, time, select, rating, image, handwriting, radio grid, checkbox grid
- **Visual form builder** — drag-and-drop form designer with live preview
- **Light & dark mode** — built-in `ThemeModeProvider` with Material UI integration
- **11 locales** — en, es, pt, fr, de, ar, ja, ko, zh, it, uk
- **Custom renderers** — override any question type with your own component
- **Theming** — customize colors, spacing, typography, and border radius
- **Three form modes** — `edit`, `readonly`, `preview`
- **Action bar** — built-in submit/reset buttons (can be hidden)
- **Conditional logic** — visibility and enabled state driven by `@question-forms/core`
- **Validation** — required, min/max, pattern, custom — with per-question error display

## Components

### QuestionForm

The main form renderer.

```tsx
import { QuestionForm } from '@question-forms/react';

<QuestionForm
    schema={schema}
    value={values}
    onChange={setValues}
    onSubmit={handleSubmit}
    onReset={handleReset}
    mode="edit"
    locale="en"
    themeMode="light"
    theme={{ primaryColor: '#6366f1' }}
    showActionBar={true}
    rendererOverrides={{ TEXT: MyCustomTextRenderer }}
/>
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `schema` | `FormSchema` | required | Form definition object |
| `value` | `FormValues` | required | Current form values |
| `onChange` | `(values: FormValues) => void` | required | Called when any value changes |
| `onSubmit` | `(values: FormValues) => void` | — | Called on valid submit |
| `onReset` | `() => void` | — | Called on reset |
| `mode` | `'edit' \| 'readonly' \| 'preview'` | `'edit'` | Form interaction mode |
| `locale` | `Locale` | `'en'` | UI translation locale |
| `themeMode` | `ThemeMode` | `'light'` | Light or dark mode |
| `theme` | `Partial<FormTheme>` | — | Theme token overrides |
| `showActionBar` | `boolean` | `true` | Show submit/reset buttons |
| `rendererOverrides` | `Partial<Record<QuestionType, Component>>` | — | Custom renderers per type |

### FormBuilder

Visual drag-and-drop form designer.

```tsx
import { useState, useCallback } from 'react';
import { FormBuilder } from '@question-forms/react';
import type { FormSchema } from '@question-forms/core';

function MyBuilder() {
    const [schema, setSchema] = useState<FormSchema | null>(null);

    const handleChange = useCallback((s: FormSchema) => {
        setSchema(s);
    }, []);

    return (
        <FormBuilder
            initialSchema={schema ?? undefined}
            onChange={handleChange}
            locale="en"
            themeMode="light"
            licenseKey="your-license-key"
        />
    );
}
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `initialSchema` | `FormSchema` | — | Pre-populate the builder |
| `onChange` | `(schema: FormSchema) => void` | — | Called on every schema change |
| `allowedTypes` | `string[]` | all types | Restrict available question types (e.g., `['TEXT:short', 'SELECT:single-select']`) |
| `colors` | `BuilderColors` | `DEFAULT_COLORS` | Builder canvas colors |
| `locale` | `Locale` | `'en'` | Builder UI locale |
| `themeMode` | `ThemeMode` | `'light'` | Light or dark mode |
| `licenseKey` | `string` | — | Required for production use |

## Custom Renderers

Override any question type with your own component:

```tsx
import type { QuestionRendererProps } from '@question-forms/react';

const MyTextRenderer = ({ question, value, onChange, disabled, errors }: QuestionRendererProps) => (
    <div>
        <label>{question.label}</label>
        <input
            value={(value as string) ?? ''}
            onChange={(e) => onChange(e.target.value)}
            disabled={disabled}
        />
        {errors.map((err, i) => (
            <span key={i} style={{ color: 'red' }}>{err}</span>
        ))}
    </div>
);

<QuestionForm
    schema={schema}
    value={values}
    onChange={setValues}
    rendererOverrides={{ TEXT: MyTextRenderer }}
/>
```

### QuestionRendererProps

| Prop | Type | Description |
|------|------|-------------|
| `question` | `QuestionSchema` | The question definition |
| `value` | `unknown` | Current value for this question |
| `onChange` | `(value: unknown) => void` | Update the value |
| `disabled` | `boolean` | Whether the input is disabled |
| `mode` | `'edit' \| 'readonly' \| 'preview'` | Current form mode |
| `errors` | `string[]` | Validation error messages |

## Theme Customization

```tsx
<QuestionForm
    schema={schema}
    value={values}
    onChange={setValues}
    theme={{
        fontFamily: '"Inter", sans-serif',
        fontSize: '14px',
        primaryColor: '#6366f1',
        errorColor: '#ef4444',
        borderColor: '#e5e7eb',
        borderRadius: '8px',
        inputPadding: '10px 14px',
        sectionGap: '32px',
        questionGap: '20px',
        labelColor: '#111827',
        disabledOpacity: 0.5,
    }}
/>
```

### Default Theme

```typescript
{
    fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
    fontSize: '14px',
    primaryColor: '#2563eb',
    errorColor: '#dc2626',
    borderColor: '#d1d5db',
    borderRadius: '6px',
    inputPadding: '8px 12px',
    sectionGap: '24px',
    questionGap: '16px',
    labelColor: '#1f2937',
    disabledOpacity: 0.6,
}
```

## Internationalization

11 built-in locales with 70+ translation strings covering form UI, builder UI, question type labels, and validation messages.

```tsx
import { QuestionForm, LOCALE_LABELS } from '@question-forms/react';
import type { Locale } from '@question-forms/react';

// Available locales
const locales = Object.entries(LOCALE_LABELS);
// [['en', 'English'], ['es', 'Español'], ['pt', 'Português'], ['fr', 'Français'], ...]

<QuestionForm
    schema={schema}
    value={values}
    onChange={setValues}
    locale="es"
/>
```

**Supported locales:** `en`, `es`, `pt`, `fr`, `de`, `ar`, `ja`, `ko`, `zh`, `it`, `uk`

## Dark Mode

```tsx
import { QuestionForm } from '@question-forms/react';

<QuestionForm
    schema={schema}
    value={values}
    onChange={setValues}
    themeMode="dark"
/>
```

The `ThemeModeProvider` wraps the form with a Material UI `ThemeProvider` configured for the selected mode.

## Builder Utilities

```typescript
import {
    useBuilderState,
    DEFAULT_COLORS,
    DEFAULT_DARK_COLORS,
    QUESTION_TYPE_LABELS,
    QUESTION_TYPE_GROUPS,
    createDefaultQuestion,
    createDefaultSection,
    createDefaultSubSection,
    generateId,
} from '@question-forms/react';
```

## Exports Summary

| Export | Description |
|--------|-------------|
| `QuestionForm` | Main form renderer component |
| `FormBuilder` | Visual form designer component |
| `defaultTheme` | Default theme values |
| `ThemeModeProvider` | Light/dark mode context provider |
| `TranslationProvider` | i18n context provider |
| `useTranslation` | Hook — access translation strings |
| `useFormContext` | Hook — access form theme, mode, overrides |
| `getTranslations` | Get translations for a locale |
| `fmt` | String formatter with `{0}`, `{1}` placeholders |
| `LOCALE_LABELS` | Map of locale codes to display names |
| `useBuilderState` | Hook — builder state management |
| `DEFAULT_COLORS` | Builder canvas colors (light) |
| `DEFAULT_DARK_COLORS` | Builder canvas colors (dark) |
| `OPTION_COLORS` | Color palette for builder |
| `QUESTION_TYPE_LABELS` | Question type display names |
| `QUESTION_TYPE_GROUPS` | Grouped question type menu config |
| `createDefaultQuestion` | Factory — new question with defaults |
| `createDefaultSection` | Factory — new section with defaults |
| `createDefaultSubSection` | Factory — new subsection with defaults |
| `generateId` | Generate unique IDs |
| `getTypeOptionKey` | Get composite type key |
| `getLocalizedGroups` | Localized question type groups |
| `getLocalizedTypeLabels` | Localized question type labels |

## License

MIT — [Question Forms SDK](https://jolly-dune-009ebe90f.4.azurestaticapps.net/)