react-smart-fields 1.1.6 โ†’ 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,190 +1,279 @@
1
- # ๐Ÿงน DynamicFields React Component
1
+ # React Smart Fields
2
2
 
3
3
  ![npm](https://img.shields.io/npm/v/react-smart-fields)
4
4
  ![downloads](https://img.shields.io/npm/dw/react-smart-fields)
5
5
  ![license](https://img.shields.io/npm/l/react-smart-fields)
6
6
 
7
+ `react-smart-fields` is a powerful dynamic form renderer for React with:
7
8
 
8
- A flexible, fully-styled dynamic form generator built with **React** and **Tailwind CSS**, supporting custom input types, validation, and class overrides. Ideal for building forms quickly with full control over design and behavior.
9
+ - configurable field schemas
10
+ - built-in + custom validation
11
+ - conditional visibility/disable/required rules
12
+ - async options for selects
13
+ - nested field names (`user.addresses[0].city`)
14
+ - theme presets + headless mode + full render slots
9
15
 
10
- ---
16
+ ## Installation
11
17
 
12
- ## โœจ Features
13
-
14
- * ๐Ÿ“ฆ Supports `text`, `number`, `checkbox`, `radio`, and `select` fields
15
- * ๐Ÿ’… Fully customizable via Tailwind-compatible className props
16
- * ๐Ÿง  Built-in required field validation
17
- * ๐Ÿงฑ Extensible for advanced usage
18
- * ๐ŸŒƒ Full **dark mode** support
19
- * ๐Ÿ”„ Real-time `onChange` callback with live `formData` and `errors`
20
-
21
- ---
22
-
23
- ## ๐Ÿ“ฆ Installation
24
-
25
- Copy the `DynamicFields.tsx` file into your React project.
26
-
27
- Make sure you have Tailwind CSS and React configured in your app.
18
+ ```bash
19
+ npm install react-smart-fields
20
+ ```
28
21
 
29
- ---
22
+ or
30
23
 
31
- ## ๐Ÿš€ Usage
24
+ ```bash
25
+ yarn add react-smart-fields
26
+ ```
32
27
 
33
- ### Basic Example
28
+ ## Quick Start
34
29
 
35
30
  ```tsx
36
- import React from "react";
37
- import DynamicFields from "./DynamicFields";
31
+ import { DynamicFields, FieldConfig } from "react-smart-fields";
38
32
 
39
- const fields = [
40
- {
41
- name: "username",
42
- label: "Username",
43
- type: "text",
44
- required: true,
45
- },
33
+ const fields: FieldConfig[] = [
34
+ { name: "name", label: "Name", type: "text", required: true },
46
35
  {
47
36
  name: "email",
48
37
  label: "Email",
49
- type: "text",
50
- required: true,
51
- },
52
- {
53
- name: "gender",
54
- label: "Gender",
55
- type: "radio",
38
+ type: "email",
56
39
  required: true,
57
- options: [
58
- { label: "Male", value: "male" },
59
- { label: "Female", value: "female" },
60
- ],
40
+ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
41
+ patternMessage: "Please enter a valid email",
61
42
  },
62
43
  {
63
44
  name: "country",
64
45
  label: "Country",
65
46
  type: "select",
47
+ placeholder: "Select country",
66
48
  options: [
67
- { label: "USA", value: "us" },
68
49
  { label: "India", value: "in" },
50
+ { label: "United States", value: "us" },
69
51
  ],
70
52
  },
71
53
  {
72
- name: "subscribe",
73
- label: "Subscribe",
54
+ name: "newsletter",
55
+ label: "Subscribe to newsletter",
74
56
  type: "checkbox",
75
- }
57
+ defaultValue: true,
58
+ },
76
59
  ];
77
60
 
78
- function App() {
79
- const handleChange = (data) => {
80
- console.log("Form Data:", data);
81
- };
82
-
61
+ export default function App() {
83
62
  return (
84
63
  <DynamicFields
85
64
  fields={fields}
86
- title="Sign Up"
87
- description="Please fill all fields"
88
- onChange={handleChange}
65
+ title="Profile"
66
+ description="Update your profile details"
67
+ theme="default"
68
+ size="md"
69
+ onChange={(values, meta) => {
70
+ console.log(values, meta?.errors);
71
+ }}
89
72
  />
90
73
  );
91
74
  }
92
75
  ```
93
76
 
94
- ---
95
-
96
- ## โš™๏ธ Props
77
+ ## Major Capabilities
78
+
79
+ - **Validation engine**: `required`, `min/max`, `minLength/maxLength`, `pattern`, and `validate`
80
+ - **Conditional behavior**: `showWhen`, `disableWhen`, `requiredWhen`
81
+ - **Nested paths**: dot/bracket field names are supported
82
+ - **Async select options**: `loadOptions` with `loadOptionsOn: "mount" | "change"`
83
+ - **Theme presets**: `default`, `minimal`, `filled`, `underline`
84
+ - **Headless mode**: set `headless` to fully control UI
85
+ - **Render slots**: `renderField`, `renderControl`, `renderLabel`, `renderDescription`, `renderError`
86
+ - **State styling hooks**: `stateClassNames` for `invalid`, `disabled`, `readonly`, `dirty`, `touched`
87
+
88
+ ## Component Props
89
+
90
+ | Prop | Type | Required | Description |
91
+ | --- | --- | --- | --- |
92
+ | `fields` | `FieldConfig[]` | โœ… | Field schema array |
93
+ | `onChange` | `(values, meta?) => void` | โœ… | Fires on every value/meta update |
94
+ | `value` | `Record<string, any>` | โŒ | Controlled mode values |
95
+ | `defaultValues` | `Record<string, any>` | โŒ | Initial values (uncontrolled mode) |
96
+ | `resolver` | `(values) => errors \| Promise<errors>` | โŒ | External validation resolver |
97
+ | `validateMode` | `"change" \| "blur"` | โŒ | Validation trigger mode |
98
+ | `showErrorWhen` | `"always" \| "touched" \| "dirty"` | โŒ | Error visibility strategy |
99
+ | `headless` | `boolean` | โŒ | Disables built-in styling |
100
+ | `theme` | `"default" \| "minimal" \| "filled" \| "underline"` | โŒ | Built-in visual preset |
101
+ | `size` | `"sm" \| "md" \| "lg"` | โŒ | Input/label sizing |
102
+ | `ui` | `UiClassMap` | โŒ | Global slot class overrides |
103
+ | `stateClassNames` | `StateClassNames` | โŒ | State class hooks |
104
+ | `renderField` | `(ctx) => ReactNode` | โŒ | Full custom field renderer |
105
+ | `renderControl` | `(ctx) => ReactNode` | โŒ | Custom control renderer |
106
+ | `renderLabel` | `(ctx) => ReactNode` | โŒ | Custom label renderer |
107
+ | `renderDescription` | `(ctx) => ReactNode` | โŒ | Custom helper text renderer |
108
+ | `renderError` | `(ctx) => ReactNode` | โŒ | Custom error renderer |
109
+ | `title` | `string` | โŒ | Form heading |
110
+ | `description` | `string` | โŒ | Form subtitle |
111
+
112
+ Legacy class props are still supported for backward compatibility:
113
+ `className`, `inputClassName`, `labelClassName`, `mainFieldClassName`, `fieldClassName`, `errorClassName`, `selectClassName`, `optionClassName`, `checkboxClassName`, `radioClassName`.
114
+
115
+ ## FieldConfig API
97
116
 
98
- | Prop | Type | Required | Description |
99
- | -------------------- | ------------------------------------- | -------- | --------------------------------- |
100
- | `fields` | `FieldConfig[]` | โœ… Yes | List of field definitions |
101
- | `onChange` | `(data: Record<string, any>) => void` | โœ… Yes | Callback on value change |
102
- | `title` | `string` | โŒ No | Optional form title |
103
- | `description` | `string` | โŒ No | Optional description |
104
- | `className` | `string` | โŒ No | Wrapper div styling |
105
- | `mainFieldClassName` | `string` | โŒ No | Class for the fields wrapper |
106
- | `inputClassName` | `string` | โŒ No | Applies to `text`/`number` inputs |
107
- | `labelClassName` | `string` | โŒ No | Applies to all labels |
108
- | `fieldClassName` | `string` | โŒ No | Applied to each field wrapper div |
109
- | `errorClassName` | `string` | โŒ No | Error message styling |
110
- | `selectClassName` | `string` | โŒ No | `select` field styling |
111
- | `checkboxClassName` | `string` | โŒ No | Checkbox input styling |
112
- | `radioClassName` | `string` | โŒ No | Radio input styling |
113
- | `optionClassName` | `string` | โŒ No | Dropdown option styling |
114
-
115
- ---
116
-
117
- ## ๐Ÿ”ง `FieldConfig` (field definition)
117
+ ```ts
118
+ type FieldConfig = {
119
+ name: string;
120
+ label?: string;
121
+ type:
122
+ | "text"
123
+ | "number"
124
+ | "select"
125
+ | "radio"
126
+ | "checkbox"
127
+ | "textarea"
128
+ | "email"
129
+ | "password"
130
+ | "tel"
131
+ | "url"
132
+ | "date";
133
+
134
+ // values/options
135
+ defaultValue?: any;
136
+ placeholder?: string;
137
+ options?: { label: string; value: string | number | boolean | null | undefined; disabled?: boolean }[];
138
+ loadOptions?: (ctx: { values: Record<string, any>; field: FieldConfig }) => Promise<FieldOption[]>;
139
+ loadOptionsOn?: "mount" | "change";
140
+
141
+ // behavior
142
+ disabled?: boolean;
143
+ readOnly?: boolean;
144
+ showWhen?: (values: Record<string, any>) => boolean;
145
+ disableWhen?: (values: Record<string, any>) => boolean;
146
+ required?: boolean;
147
+ requiredWhen?: (values: Record<string, any>) => boolean;
148
+ requiredMessage?: string;
149
+
150
+ // validation
151
+ min?: number;
152
+ max?: number;
153
+ minLength?: number;
154
+ maxLength?: number;
155
+ pattern?: RegExp;
156
+ patternMessage?: string;
157
+ validate?: (value: any, values: Record<string, any>) => string | undefined | null;
158
+
159
+ // value transforms
160
+ transformIn?: (storedValue: any, values: Record<string, any>) => any;
161
+ transformOut?: (rawValue: any, values: Record<string, any>) => any;
162
+
163
+ // styling/rendering
164
+ className?: string;
165
+ inputClassName?: string;
166
+ labelClassName?: string;
167
+ errorClassName?: string;
168
+ ui?: UiClassMap;
169
+ renderControl?: (ctx: RenderControlContext) => ReactNode;
170
+ };
171
+ ```
118
172
 
119
- Each field object can contain:
173
+ ## Customization Examples
120
174
 
121
- | Property | Type | Required | Notes |
122
- | ------------- | --------------------------------------------------------- | --------------------------------- | -------------------------------------- |
123
- | `name` | `string` | โœ… Yes | Unique key |
124
- | `label` | `string` | โŒ No | Display label |
125
- | `type` | `"text"`, `"number"`, `"select"`, `"radio"`, `"checkbox"` | โœ… Yes | Field type |
126
- | `required` | `boolean` | โŒ No | Show red asterisk and basic validation |
127
- | `placeholder` | `string` | โŒ No | Placeholder (for inputs/selects) |
128
- | `description` | `string` | โŒ No | Optional helper text |
129
- | `options` | `{ label: string; value: any; }[]` | Required for `select` and `radio` | Dropdown/Radio values |
175
+ ### 1) Conditional + Nested Fields
130
176
 
131
- ---
177
+ ```tsx
178
+ const fields: FieldConfig[] = [
179
+ { name: "accountType", label: "Account Type", type: "select", options: [
180
+ { label: "Individual", value: "individual" },
181
+ { label: "Business", value: "business" },
182
+ ]},
183
+ {
184
+ name: "company.name",
185
+ label: "Company Name",
186
+ type: "text",
187
+ showWhen: (values) => values.accountType === "business",
188
+ requiredWhen: (values) => values.accountType === "business",
189
+ },
190
+ {
191
+ name: "addresses[0].city",
192
+ label: "Primary City",
193
+ type: "text",
194
+ required: true,
195
+ },
196
+ ];
197
+ ```
132
198
 
133
- ## ๐ŸŽจ Class Mapping
199
+ ### 2) Async Select Options
134
200
 
135
- Here's how classes are applied to each section:
201
+ ```tsx
202
+ {
203
+ name: "state",
204
+ label: "State",
205
+ type: "select",
206
+ loadOptionsOn: "change",
207
+ loadOptions: async ({ values }) => {
208
+ if (!values.country) return [];
209
+ const response = await fetch(`/api/states?country=${values.country}`);
210
+ const data = await response.json();
211
+ return data.map((item: any) => ({ label: item.name, value: item.code }));
212
+ },
213
+ }
214
+ ```
136
215
 
137
- | Section | Class Prop | Default Tailwind Example |
138
- | ------------------- | ------------------- | ---------------------------------- |
139
- | Wrapper div | `className` | `bg-white dark:bg-gray-900` |
140
- | Label text | `labelClassName` | `text-gray-800 dark:text-gray-200` |
141
- | Input fields | `inputClassName` | `bg-white dark:bg-gray-800` |
142
- | Select dropdown | `selectClassName` | `rounded-lg` |
143
- | Radio buttons | `radioClassName` | `rounded-full` |
144
- | Checkbox | `checkboxClassName` | `rounded` |
145
- | Field container div | `fieldClassName` | `w-full` |
146
- | Dropdown options | `optionClassName` | `hover:bg-gray-100` |
147
- | Error messages | `errorClassName` | `text-red-500` |
216
+ ### 3) Headless + Slots
148
217
 
149
- You can override all styles with your own Tailwind classes!
218
+ ```tsx
219
+ <DynamicFields
220
+ fields={fields}
221
+ headless
222
+ renderField={({ field, labelNode, controlNode, errorNode, helpNode }) => (
223
+ <div key={field.name} className="mb-6">
224
+ {labelNode}
225
+ <div className="mt-2">{controlNode}</div>
226
+ <div className="mt-1">{helpNode}</div>
227
+ <div className="mt-1">{errorNode}</div>
228
+ </div>
229
+ )}
230
+ onChange={(values) => console.log(values)}
231
+ />
232
+ ```
150
233
 
151
- ---
234
+ ### 4) Resolver Validation
152
235
 
153
- ## ๐Ÿงช Advanced Usage: Custom Styling Per Field
236
+ ```tsx
237
+ <DynamicFields
238
+ fields={fields}
239
+ resolver={(values) => {
240
+ const errors: Record<string, string> = {};
241
+ if (values.password !== values.confirmPassword) {
242
+ errors.confirmPassword = "Passwords do not match";
243
+ }
244
+ return errors;
245
+ }}
246
+ onChange={(values, meta) => {
247
+ console.log(meta?.errors);
248
+ }}
249
+ />
250
+ ```
154
251
 
155
- You can add `inputClassName`, `labelClassName`, or `className` inside each field:
252
+ ## Type Exports
156
253
 
157
254
  ```ts
158
- {
159
- name: "email",
160
- label: "Email",
161
- type: "text",
162
- inputClassName: "border-purple-500",
163
- labelClassName: "text-purple-700 font-semibold",
164
- className: "mb-6",
165
- }
255
+ import type {
256
+ FieldConfig,
257
+ FieldOption,
258
+ FieldType,
259
+ DynamicFieldsProps,
260
+ UiClassMap,
261
+ StateClassNames,
262
+ ChangeMeta,
263
+ RenderControlContext,
264
+ RenderFieldContext,
265
+ } from "react-smart-fields";
166
266
  ```
167
267
 
168
- ---
268
+ ## Author
169
269
 
170
- ## ๐Ÿง‘โ€๐Ÿ’ป Author
171
-
172
- **Name:** Pratik Panchal
270
+ **Name:** Pratik Panchal
173
271
  **GitHub:** [@Pratikpanchal25](https://github.com/Pratikpanchal25)
174
272
 
175
- ---
176
-
177
-
178
- ## ๐Ÿ“„ License
273
+ ## License
179
274
 
180
275
  MIT โ€” Free to use, modify and distribute.
181
276
 
182
- ---
183
-
184
- ## ๐Ÿ›  Contributing
185
-
186
- Pull requests are welcome! If you find bugs, feel free to [open an issue](https://github.com/ShubhamNakum/DynamicFields/issues).
187
-
188
- ---
277
+ ## Contributing
189
278
 
190
- <!-- Keywords: react form builder, tailwind forms, dynamic form, smart form, react tailwind input -->
279
+ Pull requests are welcome! If you find bugs, feel free to open an issue.