@question-forms/react
v0.4.10
Published
React Web renderer for Question Forms SDK
Maintainers
Readme
@question-forms/react
React Web renderer for the Question Forms SDK — render schema-driven forms with Material UI, build forms visually, and customize everything.
Installation
npm install @question-forms/core @question-forms/reactPeer Dependencies
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/utilitiesQuick Start
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
ThemeModeProviderwith 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.
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.
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:
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
<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
{
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.
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
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
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
