A React component library for building and editing JSON schemas visually
npm install json-schema-builder-reactA beautiful, interactive React component for building and editing JSON schemas visually. Built with TypeScript, Tailwind CSS, and Radix UI.
- 📖 View demo
- 🎨 Visual Editor - Build JSON schemas with an intuitive interface
- 📝 Full JSON Schema Support - Support for all JSON Schema types and constraints
- 🎯 Type-Safe - Written in TypeScript with full type definitions
- ✅ Controlled Component - Full control over state management
- 🎨 Customizable - Flexible API with extensive customization options
- 🌗 Theme Support - Built-in dark mode support
- ⚡ Lightweight - Minimal bundle size with focused API
``bash`
npm install json-schema-builder-reactor
yarn add json-schema-builder-reactor
pnpm add json-schema-builder-react
This library requires the following peer dependencies to be installed in your project:
This library uses shadcn/ui components. You'll need to set up shadcn/ui and install the required components:
`bashInitialize shadcn/ui (if not already done)
npx shadcn@latest init
$3
`bash
npm install @radix-ui/react-checkbox @radix-ui/react-dialog @radix-ui/react-label @radix-ui/react-select @radix-ui/react-slot @radix-ui/react-tooltip lucide-react class-variance-authority clsx tailwind-merge
`$3
This library uses Tailwind CSS utility classes. You'll need Tailwind CSS configured in your project.
#### 1. Install Tailwind CSS (if not already installed)
`bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
`#### 2. Configure Tailwind Content Paths
Add the library to your
tailwind.config.js:`js
/* @type {import('tailwindcss').Config} /
module.exports = {
content: [
'./src/*/.{js,jsx,ts,tsx}',
'./node_modules/json-schema-builder-react/*/.{js,jsx}', // Add this line
],
theme: {
extend: {},
},
plugins: [],
};
`#### 3. Configure PostCSS
Create or update
postcss.config.js in your project root:`js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
`#### 4. Import Tailwind in your CSS
Add to your main CSS file (e.g.,
src/index.css):`css
@tailwind base;
@tailwind components;
@tailwind utilities;
`Note: The library components will automatically use your project's Tailwind theme (colors, spacing, etc.).
Usage
$3
`tsx
import { useState } from 'react';
import { JsonSchemaBuilder } from 'json-schema-builder-react';function App() {
const [schema, setSchema] = useState({
type: 'object',
properties: {},
required: []
});
return (
schema={schema}
onChange={setSchema}
/>
);
}
`$3
`tsx
import { useState } from 'react';
import { JsonSchemaBuilder } from 'json-schema-builder-react';function App() {
const [schema, setSchema] = useState({
type: 'object',
title: 'User Profile',
properties: {
name: {
type: 'string',
minLength: 2,
maxLength: 50
},
age: {
type: 'integer',
minimum: 0,
maximum: 120
}
},
required: ['name']
});
return (
schema={schema}
onChange={(newSchema) => {
setSchema(newSchema);
// Save to backend, localStorage, etc.
localStorage.setItem('schema', JSON.stringify(newSchema));
}}
/>
);
}
`$3
`tsx
import { useState } from 'react';
import { JsonSchemaBuilder } from 'json-schema-builder-react';function App() {
const [schema, setSchema] = useState({
type: 'object',
properties: {},
required: []
});
return (
schema={schema}
onChange={setSchema}
showMetadata={true}
showOutput={true}
className="h-[600px]"
typeLabels={{
string: 'Text',
boolean: 'Yes/No',
object: 'Form',
array: 'List',
}}
propertyLabel={{
singular: 'field',
plural: 'fields'
}}
/>
);
}
`$3
Since the component is fully controlled, you can implement undo/redo easily:
`tsx
import { useState } from 'react';
import { JsonSchemaBuilder } from 'json-schema-builder-react';function App() {
const [history, setHistory] = useState([{
type: 'object',
properties: {},
required: []
}]);
const [currentIndex, setCurrentIndex] = useState(0);
const currentSchema = history[currentIndex];
const handleChange = (newSchema) => {
const newHistory = history.slice(0, currentIndex + 1);
newHistory.push(newSchema);
setHistory(newHistory);
setCurrentIndex(currentIndex + 1);
};
const undo = () => {
if (currentIndex > 0) {
setCurrentIndex(currentIndex - 1);
}
};
const redo = () => {
if (currentIndex < history.length - 1) {
setCurrentIndex(currentIndex + 1);
}
};
return (
schema={currentSchema}
onChange={handleChange}
/>
);
}
`$3
By default, property keys are immutable after creation to prevent breaking existing references in your codebase. However, you can enable key editing with the
keyEditable prop:`tsx
import { useState } from 'react';
import { JsonSchemaBuilder } from 'json-schema-builder-react';function App() {
const [schema, setSchema] = useState({
type: 'object',
properties: {
user_name: {
type: 'string',
title: 'User Name'
}
},
required: []
});
return (
schema={schema}
onChange={setSchema}
keyEditable={true} // ⚠️ Allows changing keys after creation
/>
);
}
`⚠️ Warning: Enabling
keyEditable allows users to change property keys even after they've been created. This can break existing code that references these keys. Use with caution, primarily in development environments or when you have proper migration strategies in place.$3
If you only need to edit a single property without the full builder UI, you can use the
PropertyEditDialog component:`tsx
import { useState } from 'react';
import { PropertyEditDialog } from 'json-schema-builder-react';
import type { PropertyData } from 'json-schema-builder-react';function PropertyEditor() {
const [isOpen, setIsOpen] = useState(false);
const [property, setProperty] = useState({
id: '1',
key: 'username',
title: 'Username',
type: 'string',
required: true,
minLength: 3,
maxLength: 50,
});
return (
<>
property={property}
open={isOpen}
onOpenChange={setIsOpen}
onSave={(updated) => {
setProperty(updated);
// Save to your backend or state management
console.log('Updated property:', updated);
}}
isNewProperty={false}
showRegex={true}
typeLabels={{
string: 'Text',
number: 'Number',
boolean: 'Yes/No'
}}
/>
>
);
}
`API Reference
$3
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
schema | object | Required | The JSON schema object (controlled) |
| onChange | (schema: any) => void | Required | Callback when schema changes |
| showMetadata | boolean | false | Show metadata fields (title, description, version) |
| showImport | boolean | true | Show import button |
| showClear | boolean | true | Show clear all button |
| showOutput | boolean | true | Show JSON output panel |
| showHeader | boolean | true | Show header with action buttons |
| showSummary | boolean | false | Show summary at bottom |
| showRegex | boolean | false | Show regex pattern field for strings |
| keyEditable | boolean | false | Allow editing property keys after initialization (⚠️ may break references) |
| className | string | "h-screen" | Custom className for container |
| typeLabels | TypeLabels | Default labels | Custom labels for property types |
| propertyLabel | { singular: string, plural: string } | { singular: 'property', plural: 'properties' } | Custom labels for properties |$3
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
property | PropertyData | Required | The property object to edit |
| open | boolean | Required | Whether the dialog is open |
| onOpenChange | (open: boolean) => void | Required | Callback when dialog open state changes |
| onSave | (property: PropertyData) => void | Required | Callback when property is saved |
| isArrayItem | boolean | false | Whether this property is an array item |
| isNewProperty | boolean | false | Whether this is a new property (affects key editing) |
| propertyLabel | { singular: string, plural: string } | { singular: 'Property', plural: 'Properties' } | Custom labels |
| showRegex | boolean | false | Show regex pattern field for strings |
| keyEditable | boolean | false | Allow editing property key |
| typeLabels | TypeLabels | Default labels | Custom labels for property types |$3
You can customize how property types are displayed to your users:
`tsx
import { useState } from 'react';
import { JsonSchemaBuilder } from 'json-schema-builder-react';
import type { TypeLabels } from 'json-schema-builder-react';const customLabels: TypeLabels = {
string: 'Text',
number: 'Number',
integer: 'Whole Number',
boolean: 'Yes/No',
object: 'Form',
array: 'List',
null: 'Empty'
};
function App() {
const [schema, setSchema] = useState({
type: 'object',
properties: {},
required: []
});
return (
schema={schema}
onChange={setSchema}
typeLabels={customLabels}
/>
);
}
`This affects:
- The type dropdown in the property editor
- Type labels shown in property cards
- Tooltips displaying type information
Available types to customize:
-
string - Default: "String"
- number - Default: "Number"
- integer - Default: "Integer"
- boolean - Default: "Boolean"
- object - Default: "Object"
- array - Default: "Array"
- null - Default: "Null"Available Exports
$3
- JsonSchemaBuilder - Main builder component (controlled)$3
- JsonSchemaBuilderProps - Props for the main component
- TypeLabels - Type for customizing property type labelsAdvanced Usage
$3
The controlled component pattern makes it easy to integrate with any state management solution:
#### Redux
`tsx
import { useSelector, useDispatch } from 'react-redux';
import { JsonSchemaBuilder } from 'json-schema-builder-react';
import { updateSchema } from './schemaSlice';function App() {
const schema = useSelector(state => state.schema);
const dispatch = useDispatch();
return (
schema={schema}
onChange={(newSchema) => dispatch(updateSchema(newSchema))}
/>
);
}
`#### Zustand
`tsx
import { useSchemaStore } from './store';
import { JsonSchemaBuilder } from 'json-schema-builder-react';function App() {
const { schema, setSchema } = useSchemaStore();
return (
schema={schema}
onChange={setSchema}
/>
);
}
`Development
`bash
Install dependencies
npm installRun demo app in development mode
npm run devBuild the library
npm run build:libBuild the demo app
npm run buildDeploy demo to GitHub Pages
npm run deploy
`Troubleshooting
$3
If you see this warning:
`
A PostCSS plugin did not pass the from option to postcss.parse
`Solution: Make sure you have a
postcss.config.js file in your project root:`js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
`And verify your
tailwind.config.js includes the library path:`js
module.exports = {
content: [
'./src/*/.{js,jsx,ts,tsx}',
'./node_modules/json-schema-builder-react/*/.{js,jsx}',
],
// ...
};
``Make sure you:
1. Have Tailwind CSS installed and configured
2. Added the library to your Tailwind content paths (see Styling section)
3. Imported Tailwind CSS in your main CSS file
MIT © Martin Arusalu
Contributions are welcome! Please feel free to submit a Pull Request.
- 🐛 Report a bug
- 💡 Request a feature
- 📖 View demo