react-dynamic-form-builder-reactquery
v1.0.0
Published
A flexible and powerful dynamic form builder for React with Ant Design - 23 components, responsive layout, React Query integration, field dependencies, conditional fields, full TypeScript support
Maintainers
Readme
React Dynamic Form Builder
A flexible and powerful dynamic form builder for React with Ant Design support.
📖 სრული დოკუმენტაცია ქართულად - COMPLETE_GUIDE.md Comprehensive guide with all features, examples, and best practices
Features
- 🎯 Dynamic Form Generation: Create forms from configuration objects
- 🔗 Field Dependencies: Support for dependent fields (e.g., cascading selects)
- 📋 Multi-level Cascader: Hierarchical data selection (Country > City > District)
- 🔄 CRUD Modes: Create, Edit, and View modes
- 🎭 Conditional Fields: Show/hide fields based on other field values (nested support)
- 📱 Responsive & Mobile-Friendly: Full breakpoint support (xs, sm, md, lg, xl, xxl)
- ✅ Validation Rules: Comprehensive validation system (sync & async)
- 🎨 23 Custom Components: 13 Form Inputs + 10 UI Components
- 📝 isDirty Detection: Track form changes with deep equality
- 💻 TypeScript Support: Full TypeScript support with type definitions
- 📐 Flexible Layout: span, offset, push, pull with responsive support
- 🎨 Full CSS Control: No hardcoded inline styles - CSS/SCSS/Tailwind/CSS-in-JS ready
- 🔧 3 Utility Hooks: useFormDirty, useFieldDependencies, useConditionalFields
- 🌐 React Query Integration: Built-in API client with hooks (useApiQuery, useApiMutation, etc.)
- ⚡ Performance Optimized: Circular reference protection, memoization
Installation
npm install @ladojibladze/react-dynamic-form-builder
# or
yarn add @ladojibladze/react-dynamic-form-builderPeer Dependencies
This library requires the following peer dependencies:
{
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"antd": ">=5.0.0",
"@tanstack/react-query": ">=4.0.0" // Optional - only if using API integration
}Note: @tanstack/react-query is optional. Only install it if you plan to use the built-in API integration features.
Basic Usage
import { DynamicForm } from 'react-dynamic-form-builder';
const formConfig = {
fields: [
{
name: 'username',
label: 'Username',
type: 'input',
rules: [{ required: true, message: 'Please enter username' }]
},
{
name: 'email',
label: 'Email',
type: 'input',
rules: [
{ required: true, message: 'Please enter email' },
{ type: 'email', message: 'Please enter valid email' }
]
}
]
};
function App() {
const handleSubmit = (values) => {
console.log('Form values:', values);
};
return (
<DynamicForm
config={formConfig}
onSubmit={handleSubmit}
/>
);
}Advanced Features
Dependent Fields
const formConfig = {
fields: [
{
name: 'country',
label: 'Country',
type: 'select',
options: [
{ label: 'Georgia', value: 'ge' },
{ label: 'USA', value: 'us' }
]
},
{
name: 'city',
label: 'City',
type: 'select',
dependsOn: 'country',
getOptions: (countryValue) => {
// Return cities based on country
return countryValue === 'ge'
? [{ label: 'Tbilisi', value: 'tbilisi' }]
: [{ label: 'New York', value: 'ny' }];
}
}
]
};isDirty Detection
function App() {
const [isDirty, setIsDirty] = useState(false);
return (
<DynamicForm
config={formConfig}
onDirtyChange={setIsDirty}
onSubmit={handleSubmit}
/>
);
}Responsive Layout (Mobile-Friendly)
import { FormConfig, ResponsiveSpan } from 'react-dynamic-form-builder';
const responsiveConfig: FormConfig = {
fields: [
{
name: 'name',
type: 'input',
// Mobile: full width, Tablet: half, Desktop: one-third
span: { xs: 24, sm: 12, lg: 8 } as ResponsiveSpan,
},
{
name: 'email',
type: 'email',
span: { xs: 24, sm: 12, lg: 8 },
},
{
name: 'phone',
type: 'phone',
span: { xs: 24, sm: 12, lg: 8 },
},
]
};
// Breakpoints:
// xs: <576px (Mobile)
// sm: ≥576px (Tablet)
// md: ≥768px (Tablet)
// lg: ≥992px (Desktop)
// xl: ≥1200px (Large Desktop)
// xxl: ≥1600px (Extra Large)CRUD Modes
import { DynamicForm, FormMode } from 'react-dynamic-form-builder';
const [mode, setMode] = useState<FormMode>('create');
<DynamicForm
config={formConfig}
mode={mode} // 'create' | 'edit' | 'view'
initialValues={data}
onSubmit={handleSubmit}
/>Conditional Fields
const formConfig = {
fields: [
{
name: 'hasVehicle',
label: 'Do you have a vehicle?',
type: 'radio',
options: [
{ label: 'Yes', value: 'yes' },
{ label: 'No', value: 'no' }
],
conditionalFields: [
{
when: 'hasVehicle',
is: ['yes'],
fields: [
{
name: 'vehicleType',
label: 'Vehicle Type',
type: 'select',
options: [
{ label: 'Car', value: 'car' },
{ label: 'Motorcycle', value: 'motorcycle' }
]
}
]
}
]
}
]
};Custom Components (MyComponents)
ეს ბიბლიოთეკა შეიცავს 21 custom wrapper კომპონენტს, რომელთა დამოუკიდებლად გამოყენებაც შეგიძლიათ თქვენს აპლიკაციაში:
Form Input Components
MyInput
import { MyInput } from '@ladojibladze/react-dynamic-form-builder';
<MyInput
value={value}
onChange={setValue}
placeholder="Enter text"
type="text" // or "password", "email", "number", "phone"
/>MyTextArea
import { MyTextArea } from '@ladojibladze/react-dynamic-form-builder';
<MyTextArea
value={value}
onChange={setValue}
placeholder="Enter description"
rows={4}
maxLength={500}
/>MySelect
import { MySelect } from '@ladojibladze/react-dynamic-form-builder';
<MySelect
value={value}
onChange={setValue}
options={[
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' }
]}
mode="multiple" // for multiselect
showSearch
/>MyCascader
import { MyCascader } from '@ladojibladze/react-dynamic-form-builder';
<MyCascader
value={value}
onChange={setValue}
options={[
{
label: 'Georgia',
value: 'ge',
children: [
{ label: 'Tbilisi', value: 'tbilisi' },
{ label: 'Batumi', value: 'batumi' }
]
}
]}
/>MyDatePicker & MyRangePicker
import { MyDatePicker, MyRangePicker } from '@ladojibladze/react-dynamic-form-builder';
<MyDatePicker
value={date}
onChange={setDate}
format="YYYY-MM-DD"
showTime
/>
<MyRangePicker
value={dateRange}
onChange={setDateRange}
format="YYYY-MM-DD"
/>MyTimePicker & MyTimeRangePicker
import { MyTimePicker, MyTimeRangePicker } from '@ladojibladze/react-dynamic-form-builder';
<MyTimePicker
value={time}
onChange={setTime}
format="HH:mm:ss"
use12Hours={false}
/>
<MyTimeRangePicker
value={timeRange}
onChange={setTimeRange}
/>MyCheckbox & MyRadio
import { MyCheckbox, MyRadio } from '@ladojibladze/react-dynamic-form-builder';
<MyCheckbox
value={checkboxValue}
onChange={setCheckboxValue}
options={[
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' }
]}
/>
<MyRadio
value={radioValue}
onChange={setRadioValue}
options={[
{ label: 'Yes', value: 'yes' },
{ label: 'No', value: 'no' }
]}
/>MySwitch
import { MySwitch } from '@ladojibladze/react-dynamic-form-builder';
<MySwitch
value={isActive}
onChange={setIsActive}
checkedChildren="ON"
unCheckedChildren="OFF"
/>MySlider
import { MySlider } from '@ladojibladze/react-dynamic-form-builder';
<MySlider
value={sliderValue}
onChange={setSliderValue}
min={0}
max={100}
step={10}
marks={{ 0: '0°C', 100: '100°C' }}
/>MyRate
import { MyRate } from '@ladojibladze/react-dynamic-form-builder';
<MyRate
value={rating}
onChange={setRating}
count={5}
allowHalf
tooltips={['Terrible', 'Bad', 'Normal', 'Good', 'Wonderful']}
/>MyUpload
import { MyUpload } from '@ladojibladze/react-dynamic-form-builder';
<MyUpload
value={fileList}
onChange={setFileList}
uploadType="dragger" // or "button", "avatar"
maxCount={5}
accept="image/*"
/>UI Components
MyButton
import { MyButton } from '@ladojibladze/react-dynamic-form-builder';
<MyButton
buttonVariant="primary" // "secondary", "success", "danger", "warning", "info"
gradient
rounded
shadow
onClick={handleClick}
>
Click Me
</MyButton>MyCard
import { MyCard } from '@ladojibladze/react-dynamic-form-builder';
<MyCard
cardVariant="elevated" // "default", "bordered", "gradient"
shadow="lg" // "none", "sm", "md", "lg", "xl"
title="Card Title"
extra={<a href="#">More</a>}
>
Card content
</MyCard>MyModal
import { MyModal } from '@ladojibladze/react-dynamic-form-builder';
<MyModal
open={isOpen}
onOk={handleOk}
onCancel={handleCancel}
title="Modal Title"
width={600}
>
Modal content
</MyModal>MyDrawer
import { MyDrawer } from '@ladojibladze/react-dynamic-form-builder';
<MyDrawer
open={isOpen}
onClose={handleClose}
title="Drawer Title"
placement="right"
width={400}
>
Drawer content
</MyDrawer>MyPopover
import { MyPopover } from '@ladojibladze/react-dynamic-form-builder';
<MyPopover
content="Popover content"
title="Popover Title"
trigger="hover"
>
<span>Hover me</span>
</MyPopover>MyTable
import { MyTable } from '@ladojibladze/react-dynamic-form-builder';
<MyTable
dataSource={data}
columns={[
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' }
]}
tableVariant="striped" // "default", "bordered", "compact"
pagination={{ pageSize: 10 }}
/>MyCollapse
import { MyCollapse } from '@ladojibladze/react-dynamic-form-builder';
<MyCollapse
panels={[
{
key: '1',
header: 'Panel 1',
children: <p>Content 1</p>
},
{
key: '2',
header: 'Panel 2',
children: <p>Content 2</p>
}
]}
defaultActiveKey={['1']}
accordion // Only one panel open at a time
bordered={false}
ghost // Borderless style
/>MyForm & MyFormItem
import { MyForm, MyFormItem } from '@ladojibladze/react-dynamic-form-builder';
const [form] = MyForm.useForm();
<MyForm form={form} onFinish={handleSubmit}>
<MyFormItem
name="username"
label="Username"
rules={[{ required: true }]}
>
<MyInput placeholder="Enter username" />
</MyFormItem>
<MyButton type="primary" htmlType="submit">
Submit
</MyButton>
</MyForm>API
DynamicForm Props
| Prop | Type | Description | |------|------|-------------| | config | FormConfig | Form configuration object | | mode | FormMode | Form mode: 'create', 'edit', or 'view' | | initialValues | object | Initial form values | | onSubmit | (values: any) => void | Callback when form is submitted | | onChange | (values: any, changedValues: any) => void | Callback when form values change | | onDirtyChange | (isDirty: boolean) => void | Callback when form dirty state changes | | onValidationFail | (errors: any) => void | Callback when validation fails | | validateOnChange | boolean | Whether to validate on each change | | loading | boolean | Loading state | | readonly | boolean | Readonly mode | | className | string | Custom className |
FieldConfig Interface
interface FieldConfig {
name: string;
type: FieldType;
label?: string;
placeholder?: string;
defaultValue?: any;
rules?: ValidationRule[];
// Layout
span?: number | ResponsiveSpan;
offset?: number | ResponsiveSpan;
push?: number | ResponsiveSpan;
pull?: number | ResponsiveSpan;
// Options
options?: FieldOption[];
cascaderOptions?: CascaderOption[];
// Dependencies & Conditionals
dependsOn?: string | string[];
dependencies?: FieldDependency[];
conditionalFields?: ConditionalField[];
// Visibility
hidden?: boolean;
visible?: (values: any) => boolean;
visibleInModes?: FormMode[];
// Customization
disabled?: boolean;
readonly?: boolean;
style?: React.CSSProperties;
formItemStyle?: React.CSSProperties;
className?: string;
componentProps?: any;
// Form.List (for dynamic arrays)
listItemFields?: FieldConfig[];
addButtonText?: string;
removeButtonText?: string;
minItems?: number;
maxItems?: number;
}Documentation
- Quick Start: QUICK_START.md
- Layout & Responsive Guide: LAYOUT_GUIDE.md
- Features Summary: FEATURES_SUMMARY.md
- Development Guide: DEVELOPMENT.md
License
MIT
