vega-rjsf
v1.0.0
Published
React JSON Schema Form components integrated with Vega design system
Downloads
6
Maintainers
Readme
vega-rjsf
React JSON Schema Form components integrated with Vega design system.
Installation
npm install vega-rjsf
# or
yarn add vega-rjsfPeer Dependencies
This package requires the following peer dependencies:
react^19.2.1react-dom^19.2.1@vega-core(Vega design system components)
Quick Start
import { RJSFForm } from "vega-rjsf";
import type { RJSFSchema, UiSchema } from "@rjsf/utils";
const schema: RJSFSchema = {
type: "object",
properties: {
name: {
type: "string",
title: "Name",
},
email: {
type: "string",
format: "email",
title: "Email",
},
},
required: ["name", "email"],
};
const uiSchema: UiSchema = {
email: {
"ui:widget": "email",
},
};
function MyForm() {
const handleSubmit = (data: Record<string, unknown>) => {
console.log("Form submitted:", data);
};
return (
<RJSFForm
schema={schema}
uiSchema={uiSchema}
onSubmit={handleSubmit}
/>
);
}Widget Options Reference
Common Properties (All Widgets)
All widgets support these common UI schema properties:
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| ui:widget | string | - | Specifies which widget to use (see widget list below) |
| ui:label | string | Schema title | Overrides the field label from schema |
| ui:placeholder | string | - | Placeholder text for input fields |
| ui:help | string | - | Help text displayed below the field |
| ui:description | string | Schema description | Description text displayed below the field |
| ui:autofocus | boolean | false | Automatically focus the field when form loads |
| ui:emptyValue | string | undefined | Value to use when field is empty |
Widget-Specific Options
| Widget | ui:widget Value | ui:options Properties | Schema Type |
|--------|-------------------|-------------------------|-------------|
| Text | "text" | inputType?: "text" \| "email" \| "password" \| "tel" | string |
| Textarea | "textarea" | rows?: number (default: 4) | string |
| Number | "number" | None | number |
| Select | "select" | enumOptions?: Array<{ label: string; value: string }> | string with enum |
| Radio | "radio" | inline?: boolean (default: false)enumOptions?: Array<{ label: string; value: string }> | string with enum |
| Radio Cards | "radioCards" | columns?: 2 \| 3 \| 4 (default: 2)enumOptions?: Array<{ label: string; value: string }> | string with enum |
| Checkbox | "checkbox" | None | boolean |
| Checkboxes | "checkboxes" | columns?: 2 \| 3 \| 4 (default: 2)enumOptions?: Array<{ label: string; value: string }> | array with enum items |
| Switch | "switch" | None | boolean |
| Segmented Tabs | "segmentedTabs" | enumOptions?: Array<{ label: string; value: string }> | string with enum |
Quick Reference Table
| Property | Text | Textarea | Number | Select | Radio | Radio Cards | Checkbox | Checkboxes | Switch | Segmented Tabs |
|----------|:----:|:--------:|:------:|:------:|:----:|:-----------:|:--------:|:----------:|:------:|:--------------:|
| ui:label | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| ui:placeholder | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| ui:help | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| ui:description | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| ui:autofocus | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| ui:emptyValue | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| ui:options.inputType | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| ui:options.rows | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| ui:options.inline | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| ui:options.columns | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ |
| ui:options.enumOptions | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ |
TypeScript Types
All widget options are available as TypeScript types:
import type {
CommonWidgetOptions,
TextWidgetOptions,
TextareaWidgetOptions,
NumberWidgetOptions,
SelectWidgetOptions,
RadioWidgetOptions,
RadioCardsWidgetOptions,
CheckboxWidgetOptions,
CheckboxesWidgetOptions,
SwitchWidgetOptions,
SegmentedTabsWidgetOptions,
WidgetOptions,
SubmitButtonOptions,
} from "vega-rjsf";Example
const uiSchema: UiSchema = {
myField: {
"ui:label": "Custom Label",
"ui:placeholder": "Enter value",
"ui:help": "This is helpful information",
"ui:description": "This is a description",
"ui:autofocus": true,
"ui:emptyValue": "",
"ui:widget": "text",
"ui:options": {
inputType: "email",
},
},
};Widgets
Text Widget (text)
Default widget for string fields. Supports various input types based on schema format or explicit configuration.
Schema:
{
"type": "string",
"title": "Text Field"
}UI Schema Options:
{
"ui:widget": "text",
"ui:options": {
"inputType": "text" | "email" | "password" | "tel" // Optional, auto-detected from format
}
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
username: {
type: "string",
title: "Username",
},
email: {
type: "string",
format: "email",
title: "Email",
},
password: {
type: "string",
title: "Password",
},
},
};
const uiSchema: UiSchema = {
password: {
"ui:widget": "text",
"ui:options": {
inputType: "password",
},
},
};Textarea Widget (textarea)
Multi-line text input for longer text content.
Schema:
{
"type": "string",
"title": "Description"
}UI Schema Options:
{
"ui:widget": "textarea",
"ui:options": {
"rows": number // Number of rows (default: 4)
}
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
description: {
type: "string",
title: "Description",
},
},
};
const uiSchema: UiSchema = {
description: {
"ui:widget": "textarea",
"ui:placeholder": "Enter a detailed description",
"ui:options": {
rows: 6,
},
},
};Number Widget (number)
Numeric input with proper number formatting and validation.
Schema:
{
"type": "number",
"title": "Amount"
}UI Schema Options:
{
"ui:widget": "number"
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
amount: {
type: "number",
title: "Amount",
minimum: 0,
},
},
};
const uiSchema: UiSchema = {
amount: {
"ui:widget": "number",
"ui:placeholder": "0.00",
},
};Select Widget (select)
Dropdown select for single value selection from a list of options.
Schema:
{
"type": "string",
"title": "Country",
"enum": ["US", "UK", "CA"],
"enumNames": ["United States", "United Kingdom", "Canada"]
}UI Schema Options:
{
"ui:widget": "select",
"ui:options": {
"enumOptions": Array<{ label: string; value: string }> // Override enum/enumNames
}
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
country: {
type: "string",
title: "Country",
enum: ["US", "UK", "CA"],
enumNames: ["United States", "United Kingdom", "Canada"],
},
},
};
const uiSchema: UiSchema = {
country: {
"ui:widget": "select",
"ui:placeholder": "Select a country",
// Optional: override enum options
"ui:options": {
enumOptions: [
{ label: "United States", value: "US" },
{ label: "United Kingdom", value: "UK" },
{ label: "Canada", value: "CA" },
],
},
},
};Radio Widget (radio)
Radio button group for single selection.
Schema:
{
"type": "string",
"title": "Option",
"enum": ["option1", "option2", "option3"],
"enumNames": ["Option 1", "Option 2", "Option 3"]
}UI Schema Options:
{
"ui:widget": "radio",
"ui:options": {
"inline": boolean, // Display horizontally (default: false)
"enumOptions": Array<{ label: string; value: string }> // Override enum/enumNames
}
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
plan: {
type: "string",
title: "Select Plan",
enum: ["basic", "premium", "enterprise"],
enumNames: ["Basic", "Premium", "Enterprise"],
},
},
};
const uiSchema: UiSchema = {
plan: {
"ui:widget": "radio",
"ui:options": {
inline: true, // Display horizontally
},
},
};Radio Cards Widget (radioCards)
Card-based radio selection with visual cards for each option.
Schema:
{
"type": "string",
"title": "Payment Method",
"enum": ["credit", "debit", "paypal"],
"enumNames": ["Credit Card", "Debit Card", "PayPal"]
}UI Schema Options:
{
"ui:widget": "radioCards",
"ui:options": {
"columns": number, // Grid columns: 2, 3, or 4 (default: 2)
"enumOptions": Array<{ label: string; value: string }> // Override enum/enumNames
}
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
paymentMethod: {
type: "string",
title: "Payment Method",
enum: ["credit", "debit", "paypal"],
enumNames: ["Credit Card", "Debit Card", "PayPal"],
},
},
};
const uiSchema: UiSchema = {
paymentMethod: {
"ui:widget": "radioCards",
"ui:options": {
columns: 3, // Display in 3 columns
},
},
};Checkbox Widget (checkbox)
Single checkbox for boolean values.
Schema:
{
"type": "boolean",
"title": "I agree to the terms"
}UI Schema Options:
{
"ui:widget": "checkbox"
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
agreeToTerms: {
type: "boolean",
title: "I agree to the terms and conditions",
},
},
};
const uiSchema: UiSchema = {
agreeToTerms: {
"ui:widget": "checkbox",
"ui:help": "You must agree to continue",
},
};Checkboxes Widget (checkboxes)
Multiple checkboxes for array of selected values.
Schema:
{
"type": "array",
"title": "Interests",
"items": {
"type": "string",
"enum": ["sports", "music", "travel"],
"enumNames": ["Sports", "Music", "Travel"]
}
}UI Schema Options:
{
"ui:widget": "checkboxes",
"ui:options": {
"columns": number, // Grid columns: 2, 3, or 4 (default: 2)
"enumOptions": Array<{ label: string; value: string }> // Override enum/enumNames
}
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
interests: {
type: "array",
title: "Select Your Interests",
items: {
type: "string",
enum: ["sports", "music", "travel", "reading"],
enumNames: ["Sports", "Music", "Travel", "Reading"],
},
uniqueItems: true,
},
},
};
const uiSchema: UiSchema = {
interests: {
"ui:widget": "checkboxes",
"ui:options": {
columns: 2, // Display in 2 columns
},
},
};Switch Widget (switch)
Toggle switch for boolean values.
Schema:
{
"type": "boolean",
"title": "Enable notifications"
}UI Schema Options:
{
"ui:widget": "switch"
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
notifications: {
type: "boolean",
title: "Enable Email Notifications",
},
},
};
const uiSchema: UiSchema = {
notifications: {
"ui:widget": "switch",
"ui:help": "Receive email updates about your account",
},
};Segmented Tabs Widget (segmentedTabs)
Segmented tab selection for single value selection.
Schema:
{
"type": "string",
"title": "View Mode",
"enum": ["list", "grid", "card"],
"enumNames": ["List", "Grid", "Card"]
}UI Schema Options:
{
"ui:widget": "segmentedTabs",
"ui:options": {
"enumOptions": Array<{ label: string; value: string }> // Override enum/enumNames
}
}Example:
const schema: RJSFSchema = {
type: "object",
properties: {
viewMode: {
type: "string",
title: "View Mode",
enum: ["list", "grid", "card"],
enumNames: ["List", "Grid", "Card"],
},
},
};
const uiSchema: UiSchema = {
viewMode: {
"ui:widget": "segmentedTabs",
},
};Submit Button Customization
Customize the submit button text via the root-level UI schema:
const uiSchema: UiSchema = {
"ui:submitButtonOptions": {
submitText: "Save Changes", // Custom button text
},
// ... field-specific UI schemas
};Backend Validation Errors
The form supports backend validation errors in RJSF's ErrorSchema format. Backend should send errors directly in this format:
import type { ErrorSchema } from "@rjsf/utils";
const backendErrors: ErrorSchema = {
name: {
__errors: ["Name is required"],
},
email: {
__errors: ["Invalid email format", "Email must be unique"],
},
amount: {
__errors: ["Amount exceeds maximum allowed"],
},
};
<RJSFForm
schema={schema}
uiSchema={uiSchema}
extraErrors={backendErrors}
onSubmit={handleSubmit}
/>Error Schema Format
type ErrorSchema = {
[fieldName: string]: {
__errors: string[];
} & ErrorSchema; // Recursive for nested fields
};Example with nested fields:
const nestedErrors: ErrorSchema = {
address: {
street: {
__errors: ["Street is required"],
},
city: {
__errors: ["City is required"],
},
},
};Complete Example
import { RJSFForm } from "vega-rjsf";
import type { ErrorSchema, RJSFSchema, UiSchema } from "@rjsf/utils";
import { useState } from "react";
const schema: RJSFSchema = {
type: "object",
properties: {
name: {
type: "string",
title: "Full Name",
},
email: {
type: "string",
format: "email",
title: "Email Address",
},
country: {
type: "string",
title: "Country",
enum: ["US", "UK", "CA"],
enumNames: ["United States", "United Kingdom", "Canada"],
},
interests: {
type: "array",
title: "Interests",
items: {
type: "string",
enum: ["sports", "music", "travel"],
enumNames: ["Sports", "Music", "Travel"],
},
uniqueItems: true,
},
notifications: {
type: "boolean",
title: "Enable Notifications",
},
},
required: ["name", "email"],
};
const uiSchema: UiSchema = {
"ui:submitButtonOptions": {
submitText: "Create Account",
},
email: {
"ui:placeholder": "[email protected]",
"ui:help": "We'll never share your email",
},
country: {
"ui:widget": "select",
},
interests: {
"ui:widget": "checkboxes",
"ui:options": {
columns: 3,
},
},
notifications: {
"ui:widget": "switch",
},
};
function MyForm() {
const [errors, setErrors] = useState<ErrorSchema | undefined>();
const handleSubmit = async (data: Record<string, unknown>) => {
// Simulate API call
try {
const response = await fetch("/api/submit", {
method: "POST",
body: JSON.stringify(data),
});
if (!response.ok) {
const errorData = await response.json();
// Backend should return ErrorSchema format
setErrors(errorData.errors);
return;
}
console.log("Success:", data);
setErrors(undefined);
} catch (error) {
console.error("Error:", error);
}
};
return (
<RJSFForm
schema={schema}
uiSchema={uiSchema}
extraErrors={errors}
onSubmit={handleSubmit}
/>
);
}TypeScript Support
All types are exported from the package:
import type {
RJSFFormProps,
ErrorSchema,
// Widget option types
CommonWidgetOptions,
TextWidgetOptions,
TextareaWidgetOptions,
NumberWidgetOptions,
SelectWidgetOptions,
RadioWidgetOptions,
RadioCardsWidgetOptions,
CheckboxWidgetOptions,
CheckboxesWidgetOptions,
SwitchWidgetOptions,
SegmentedTabsWidgetOptions,
WidgetOptions,
SubmitButtonOptions,
} from "vega-rjsf";
import type { RJSFSchema, UiSchema } from "@rjsf/utils";License
UNLICENSED
