npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

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-builder

Peer 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

License

MIT