@fivexlabs/conform-react
Version:
๐ A powerful React library for building dynamic, conditional forms using JSON schemas with React Hook Form integration. Create complex forms declaratively with built-in validation, accessibility, and customizable components. Made with โค๏ธ by Fivex Labs.
533 lines (453 loc) โข 13 kB
Markdown
# @fivexlabs/conform-react
<div align="center">
<img src="https://fivexlabs.com/assets/icon/logos/icon-logo-square.jpeg" alt="Fivex Labs" width="80" height="80" />
<h3>React JSON Form Renderer</h3>
<p>Build dynamic, conditional forms using JSON schemas with React Hook Form integration</p>
<p>Made with โค๏ธ by <a href="https://fivexlabs.com">Fivex Labs</a></p>
[](https://www.npmjs.com/package/@fivexlabs/conform-react)
[](https://opensource.org/licenses/MIT)
[](http://www.typescriptlang.org/)
</div>
## โจ Features
### ๐ฏ **Core Features**
- **๐ Declarative Schema Definition**: Define entire forms using JSON schemas
- **๐ Dynamic Conditional Logic**: Show/hide fields based on other field values
- **โ
Comprehensive Validation**: Built-in and custom validation with internationalization support
- **๐จ Customizable Components**: Provide your own React components for any field type
- **โฟ Accessibility First**: WCAG compliant forms with proper ARIA attributes
- **๐ Performance Optimized**: Built on React Hook Form for optimal performance
- **๐ฆ TypeScript Ready**: Full TypeScript support with comprehensive type definitions
### ๐ฅ **Advanced Features** (New!)
- **๐ Smart File Upload**: Drag & drop interface with progress tracking, image preview, and validation
- **๐ Async Autocomplete**: Search-as-you-type with debouncing, templates, and API integration
- **๐
Business Date/Time Picker**: Business rules, timezone support, and restriction handling
- **๐ Cross-field Validation**: Dependencies between fields with real-time validation
- **๐งฎ Computed Fields**: Auto-calculated values based on other field data
- **โก Real-time Updates**: Live form state management and analytics
## ๐ฆ Installation
```bash
npm install @fivexlabs/conform-react react-hook-form yup date-fns
# or
yarn add @fivexlabs/conform-react react-hook-form yup date-fns
```
> **Note**: `date-fns` is required for the advanced date/time picker functionality.
## ๐ Quick Start
```tsx
import React from 'react';
import { FormRenderer, FormSchema } from '@fivexlabs/conform-react';
const schema: FormSchema = {
title: "User Registration",
fields: [
{
name: "fullName",
label: "Full Name",
type: "text",
validation: { required: true, minLength: 2 }
},
{
name: "email",
label: "Email Address",
type: "email",
validation: { required: true, email: true }
},
{
name: "subscribe",
label: "Subscribe to newsletter?",
type: "checkbox",
defaultValue: false
},
{
name: "reason",
label: "Why do you want to subscribe?",
type: "textarea",
visibleWhen: { subscribe: true },
validation: { required: true, maxLength: 200 }
}
]
};
function App() {
const handleSubmit = (data: Record<string, any>) => {
console.log('Form submitted:', data);
};
return (
<FormRenderer
schema={schema}
onSubmit={handleSubmit}
onFormChange={(data) => console.log('Form changed:', data)}
/>
);
}
```
## ๐ฅ Advanced Features Showcase
### ๐ Smart File Upload
Create powerful file upload experiences with drag & drop, progress tracking, and validation:
```typescript
{
name: "documents",
type: "fileUpload",
label: "Project Documents",
props: {
multiple: true,
accept: ['.pdf', '.docx', '.jpg', '.png'],
maxSize: 10 * 1024 * 1024, // 10MB
maxFiles: 5,
preview: true,
upload: {
endpoint: '/api/upload',
method: 'POST',
headers: { 'Authorization': 'Bearer token123' }
}
},
onUploadProgress: (progress, file) => console.log(`${file.name}: ${progress}%`),
onUploadComplete: (response, file) => console.log('Upload completed:', response)
}
```
### ๐ Async Autocomplete
Build smart search interfaces with real-time suggestions:
```typescript
{
name: "assignee",
type: "autocomplete",
label: "Project Assignee",
props: {
searchEndpoint: '/api/users/search',
displayKey: 'name',
valueKey: 'id',
debounce: 300,
minChars: 2,
template: '{{name}} - {{department}} ({{email}})',
multiple: false
}
}
```
### ๐
Business Date/Time Picker
Handle complex business rules with smart date/time selection:
```typescript
{
name: "deadline",
type: "dateTime",
label: "Project Deadline",
props: {
includeTime: true,
format: 'yyyy-MM-dd HH:mm',
restrictions: {
minDate: 'today',
businessDaysOnly: true,
disabledDays: ['saturday', 'sunday'],
disabledDates: ['2024-12-25', '2024-01-01']
}
}
}
```
### ๐ Cross-field Validation
Create intelligent forms with field dependencies:
```typescript
{
name: "endDate",
type: "dateTime",
label: "Project End Date",
validation: {
custom: async (value, formData) => {
if (value <= formData.startDate) {
return 'End date must be after start date';
}
return true;
},
dependencies: ['startDate'] // Re-validate when startDate changes
}
}
```
### ๐งฎ Computed Fields
Auto-calculate values based on other field data:
```typescript
{
name: "totalCost",
type: "text",
label: "Total Cost",
props: { disabled: true }, // Read-only
computed: {
formula: (formData) => {
const hours = formData.estimatedHours || 0;
const rate = formData.hourlyRate || 0;
return `$${(hours * rate).toFixed(2)}`;
},
dependencies: ['estimatedHours', 'hourlyRate']
}
}
```
## ๐ Documentation
### Basic Form Schema
A form schema defines the structure, validation, and behavior of your form:
```typescript
interface FormSchema {
title?: string;
description?: string;
fields: (FormField | FieldGroup)[];
layout?: LayoutConfig;
submitButtonText?: string;
resetButtonText?: string;
showResetButton?: boolean;
}
```
### Field Types
#### Text Input Fields
```typescript
{
name: "username",
label: "Username",
type: "text", // "text" | "email" | "password" | "url" | "tel"
placeholder: "Enter your username",
validation: {
required: true,
minLength: 3,
pattern: "^[a-zA-Z0-9_]+$"
},
validationMessages: {
pattern: "Username can only contain letters, numbers, and underscores"
}
}
```
#### Select Fields
```typescript
{
name: "country",
label: "Country",
type: "select",
options: [
{ label: "United States", value: "us" },
{ label: "Canada", value: "ca" },
{ label: "United Kingdom", value: "uk" }
],
validation: { required: true }
}
```
#### Array Fields (Repeatable Sections)
```typescript
{
name: "addresses",
label: "Addresses",
type: "array",
minItems: 1,
maxItems: 3,
itemSchema: {
fields: [
{
name: "street",
label: "Street Address",
type: "text",
validation: { required: true }
},
{
name: "city",
label: "City",
type: "text",
validation: { required: true }
}
]
}
}
```
### Conditional Logic
#### Simple Conditional Syntax
```typescript
{
name: "otherReason",
label: "Please specify",
type: "text",
visibleWhen: { reason: "other" }, // Show when reason equals "other"
disabledWhen: { status: "readonly" } // Disable when status equals "readonly"
}
```
#### Advanced Conditional Logic
```typescript
{
name: "discount",
label: "Discount Code",
type: "text",
conditional: {
and: [
{ field: "membershipType", operator: "equals", value: "premium" },
{ field: "orderAmount", operator: "greaterThan", value: 100 }
]
}
}
```
#### Complex Conditions with MongoDB-style Operators
```typescript
{
name: "specialOffer",
label: "Special Offer",
type: "checkbox",
visibleWhen: {
age: { $gte: 18 },
country: { $in: ["us", "ca", "uk"] },
email: { $contains: "@company.com" }
}
}
```
### Validation
#### Built-in Validation Rules
```typescript
{
validation: {
required: true,
minLength: 5,
maxLength: 50,
min: 0,
max: 100,
pattern: "^[A-Z][a-z]+$",
email: true // For email fields
}
}
```
#### Custom Validation
```typescript
{
validation: {
custom: async (value) => {
// Async validation example
const isUnique = await checkUsernameUniqueness(value);
return isUnique || "Username is already taken";
}
}
}
```
### Field Groups
```typescript
{
type: "group",
title: "Personal Information",
description: "Please provide your personal details",
collapsible: true,
fields: [
{
name: "firstName",
label: "First Name",
type: "text",
validation: { required: true }
},
{
name: "lastName",
label: "Last Name",
type: "text",
validation: { required: true }
}
]
}
```
### Custom Components
You can provide your own React components for any field type:
```tsx
import { TextField } from '@mui/material';
const customComponents = {
text: ({ field, value, onChange, error, ...props }) => (
<TextField
label={field.label}
value={value || ''}
onChange={(e) => onChange(e.target.value)}
error={!!error}
helperText={error}
fullWidth
{...props}
/>
),
select: CustomSelectComponent,
// ... other custom components
};
<FormRenderer
schema={schema}
customComponents={customComponents}
onSubmit={handleSubmit}
/>
```
### Advanced Usage
#### Custom Rendering
```tsx
<FormRenderer
schema={schema}
onSubmit={handleSubmit}
renderSubmitButton={(props) => (
<CustomButton loading={props.loading} onClick={props.onClick}>
{props.text}
</CustomButton>
)}
renderErrorSummary={(errors) => (
<CustomErrorDisplay errors={errors} />
)}
renderFieldWrapper={({ field, children, error }) => (
<div className="custom-field-wrapper">
{children}
{error && <span className="error-icon">โ ๏ธ</span>}
</div>
)}
/>
```
#### Form State Management
```tsx
const FormWithState = () => {
const [formData, setFormData] = useState({});
return (
<FormRenderer
schema={schema}
initialValues={{ username: 'defaultUser' }}
onSubmit={handleSubmit}
onFormChange={setFormData}
onFieldChange={(fieldName, value, allValues) => {
console.log(`Field ${fieldName} changed to:`, value);
}}
/>
);
};
```
## ๐จ Styling
The library provides unstyled components by default with semantic CSS classes for easy styling:
```css
.conform-form {
/* Main form container */
}
.form-field {
/* Individual field wrapper */
}
.form-group {
/* Field group container */
}
.form-error {
/* Error message styling */
}
```
For Tailwind CSS users, the default components include Tailwind classes that you can customize.
## ๐งช Testing
```bash
npm test
```
## ๐ API Reference
### FormRenderer Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `schema` | `FormSchema` | โ
| The JSON schema defining the form structure |
| `onSubmit` | `(data: Record<string, any>) => void \| Promise<void>` | โ
| Called when form is submitted |
| `initialValues` | `Record<string, any>` | โ | Initial form values |
| `onFormChange` | `(data: Record<string, any>) => void` | โ | Called when any field changes |
| `onFieldChange` | `(fieldName: string, value: any, allValues: Record<string, any>) => void` | โ | Called when a specific field changes |
| `customComponents` | `Record<string, React.ComponentType<any>>` | โ | Custom components for field types |
| `loading` | `boolean` | โ | Shows loading state |
| `disabled` | `boolean` | โ | Disables entire form |
## ๐ Changelog
See [CHANGELOG.md](CHANGELOG.md) for a detailed history of all changes and new features.
## ๐ค Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## ๐ License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## ๐ข About Fivex Labs
[Fivex Labs](https://fivexlabs.com) is a technology company focused on building innovative tools and libraries for modern web development. We believe in creating solutions that are both powerful and developer-friendly.
Visit us at [fivexlabs.com](https://fivexlabs.com) to learn more about our work and other open-source projects.
<div align="center">
<p>Made with โค๏ธ by <a href="https://fivexlabs.com">Fivex Labs</a></p>
<p>ยฉ 2025 Fivex Labs. All rights reserved.</p>
</div>