0
# Forms & Inputs
1
2
React Admin provides a comprehensive form system built on React Hook Form, offering rich input components, validation, and sophisticated form handling capabilities. The system supports complex scenarios including nested forms, arrays, relationships, and multi-step workflows.
3
4
## Form Component
5
6
The `<Form>` component is the foundation of form handling in React Admin, providing form context and validation.
7
8
```typescript { .api }
9
import { Form } from 'react-admin';
10
11
interface FormProps {
12
defaultValues?: any;
13
record?: RaRecord;
14
validate?: ValidateForm;
15
resolver?: any;
16
onSubmit?: (data: any) => void | Promise<void>;
17
sanitizeEmptyValues?: boolean;
18
warnWhenUnsavedChanges?: boolean;
19
noValidate?: boolean;
20
children: React.ReactNode;
21
id?: string;
22
className?: string;
23
sx?: any;
24
}
25
26
const Form: React.FC<FormProps>;
27
28
type ValidateForm = (values: any) => any | Promise<any>;
29
```
30
31
### Form Usage Example
32
33
```typescript
34
import { Form, TextInput, SaveButton } from 'react-admin';
35
36
const PostForm = ({ record, onSave }) => (
37
<Form
38
record={record}
39
onSubmit={onSave}
40
validate={(values) => {
41
const errors: any = {};
42
if (!values.title) errors.title = 'Title is required';
43
if (!values.content) errors.content = 'Content is required';
44
return errors;
45
}}
46
>
47
<TextInput source="title" label="Title" required />
48
<TextInput source="content" label="Content" multiline rows={4} />
49
<SaveButton />
50
</Form>
51
);
52
```
53
54
## Text Inputs
55
56
### TextInput
57
58
Basic text input for single-line text.
59
60
```typescript { .api }
61
import { TextInput } from 'react-admin';
62
63
interface TextInputProps {
64
source: string;
65
label?: string | false;
66
helperText?: string | false;
67
defaultValue?: any;
68
format?: (value: any) => any;
69
parse?: (value: any) => any;
70
validate?: Function | Function[];
71
required?: boolean;
72
disabled?: boolean;
73
readOnly?: boolean;
74
multiline?: boolean;
75
rows?: number;
76
maxRows?: number;
77
type?: 'text' | 'email' | 'url' | 'tel' | 'password';
78
placeholder?: string;
79
fullWidth?: boolean;
80
margin?: 'none' | 'dense' | 'normal';
81
variant?: 'standard' | 'outlined' | 'filled';
82
InputProps?: any;
83
inputProps?: any;
84
className?: string;
85
sx?: any;
86
}
87
88
const TextInput: React.FC<TextInputProps>;
89
```
90
91
#### Usage Examples
92
93
```typescript
94
// Basic text input
95
<TextInput source="title" label="Post Title" />
96
97
// Multiline text input
98
<TextInput source="content" label="Content" multiline rows={4} />
99
100
// Email input with validation
101
<TextInput
102
source="email"
103
label="Email"
104
type="email"
105
validate={[required(), email()]}
106
/>
107
108
// Password input
109
<TextInput source="password" label="Password" type="password" />
110
111
// Custom format and parse
112
<TextInput
113
source="slug"
114
format={value => value?.toLowerCase().replace(/\s+/g, '-')}
115
parse={value => value?.toLowerCase().replace(/\s+/g, '-')}
116
/>
117
```
118
119
### NumberInput
120
121
Numeric input with number formatting and validation.
122
123
```typescript { .api }
124
import { NumberInput } from 'react-admin';
125
126
interface NumberInputProps extends Omit<TextInputProps, 'type'> {
127
min?: number;
128
max?: number;
129
step?: number;
130
}
131
132
const NumberInput: React.FC<NumberInputProps>;
133
```
134
135
#### Usage Example
136
137
```typescript
138
<NumberInput
139
source="price"
140
label="Price"
141
min={0}
142
step={0.01}
143
validate={[required(), minValue(0)]}
144
/>
145
```
146
147
### PasswordInput
148
149
Password input with show/hide toggle.
150
151
```typescript { .api }
152
import { PasswordInput } from 'react-admin';
153
154
const PasswordInput: React.FC<TextInputProps>;
155
```
156
157
## Selection Inputs
158
159
### SelectInput
160
161
Dropdown selection for choosing from predefined options.
162
163
```typescript { .api }
164
import { SelectInput } from 'react-admin';
165
166
interface SelectInputProps {
167
source: string;
168
choices: ChoiceType[];
169
optionText?: string | Function;
170
optionValue?: string;
171
translateChoice?: boolean;
172
disableValue?: string | Function;
173
emptyText?: string;
174
emptyValue?: any;
175
label?: string | false;
176
validate?: Function | Function[];
177
defaultValue?: any;
178
fullWidth?: boolean;
179
margin?: 'none' | 'dense' | 'normal';
180
variant?: 'standard' | 'outlined' | 'filled';
181
className?: string;
182
sx?: any;
183
}
184
185
interface ChoiceType {
186
id: any;
187
name?: string;
188
[key: string]: any;
189
}
190
191
const SelectInput: React.FC<SelectInputProps>;
192
```
193
194
#### Usage Example
195
196
```typescript
197
const statusChoices = [
198
{ id: 'draft', name: 'Draft' },
199
{ id: 'published', name: 'Published' },
200
{ id: 'archived', name: 'Archived' }
201
];
202
203
<SelectInput
204
source="status"
205
choices={statusChoices}
206
label="Status"
207
defaultValue="draft"
208
/>
209
```
210
211
### AutocompleteInput
212
213
Autocomplete input with search and filtering.
214
215
```typescript { .api }
216
import { AutocompleteInput } from 'react-admin';
217
218
interface AutocompleteInputProps {
219
source: string;
220
choices: ChoiceType[];
221
optionText?: string | Function;
222
optionValue?: string;
223
matchSuggestion?: Function;
224
shouldRenderSuggestions?: Function;
225
inputText?: Function;
226
setFilter?: Function;
227
filterToQuery?: Function;
228
freeSolo?: boolean;
229
multiple?: boolean;
230
clearOnBlur?: boolean;
231
onCreate?: Function;
232
createLabel?: string;
233
createItemLabel?: string;
234
noOptionsText?: string;
235
label?: string | false;
236
validate?: Function | Function[];
237
debounce?: number;
238
className?: string;
239
sx?: any;
240
}
241
242
const AutocompleteInput: React.FC<AutocompleteInputProps>;
243
```
244
245
#### Usage Example
246
247
```typescript
248
const tagChoices = [
249
{ id: 1, name: 'Technology' },
250
{ id: 2, name: 'React' },
251
{ id: 3, name: 'JavaScript' }
252
];
253
254
<AutocompleteInput
255
source="tags"
256
choices={tagChoices}
257
multiple
258
create
259
label="Tags"
260
onCreate={(filter) => {
261
const newTag = { id: Date.now(), name: filter };
262
// Add to choices or save to backend
263
return newTag;
264
}}
265
/>
266
```
267
268
### RadioButtonGroupInput
269
270
Radio button group for single selection.
271
272
```typescript { .api }
273
import { RadioButtonGroupInput } from 'react-admin';
274
275
interface RadioButtonGroupInputProps {
276
source: string;
277
choices: ChoiceType[];
278
optionText?: string | Function;
279
optionValue?: string;
280
translateChoice?: boolean;
281
label?: string | false;
282
validate?: Function | Function[];
283
row?: boolean;
284
className?: string;
285
sx?: any;
286
}
287
288
const RadioButtonGroupInput: React.FC<RadioButtonGroupInputProps>;
289
```
290
291
### CheckboxGroupInput
292
293
Checkbox group for multiple selection.
294
295
```typescript { .api }
296
import { CheckboxGroupInput } from 'react-admin';
297
298
interface CheckboxGroupInputProps {
299
source: string;
300
choices: ChoiceType[];
301
optionText?: string | Function;
302
optionValue?: string;
303
translateChoice?: boolean;
304
label?: string | false;
305
validate?: Function | Function[];
306
row?: boolean;
307
className?: string;
308
sx?: any;
309
}
310
311
const CheckboxGroupInput: React.FC<CheckboxGroupInputProps>;
312
```
313
314
## Boolean Inputs
315
316
### BooleanInput
317
318
Checkbox for boolean values.
319
320
```typescript { .api }
321
import { BooleanInput } from 'react-admin';
322
323
interface BooleanInputProps {
324
source: string;
325
label?: string | false;
326
helperText?: string | false;
327
defaultValue?: boolean;
328
format?: (value: any) => boolean;
329
parse?: (value: boolean) => any;
330
validate?: Function | Function[];
331
disabled?: boolean;
332
readOnly?: boolean;
333
color?: 'primary' | 'secondary' | 'default';
334
size?: 'small' | 'medium';
335
className?: string;
336
sx?: any;
337
}
338
339
const BooleanInput: React.FC<BooleanInputProps>;
340
```
341
342
### NullableBooleanInput
343
344
Three-state boolean input (true/false/null).
345
346
```typescript { .api }
347
import { NullableBooleanInput } from 'react-admin';
348
349
const NullableBooleanInput: React.FC<SelectInputProps>;
350
```
351
352
#### Usage Example
353
354
```typescript
355
<NullableBooleanInput
356
source="featured"
357
label="Featured"
358
nullLabel="Not Set"
359
falseLabel="No"
360
trueLabel="Yes"
361
/>
362
```
363
364
## Date and Time Inputs
365
366
### DateInput
367
368
Date picker input.
369
370
```typescript { .api }
371
import { DateInput } from 'react-admin';
372
373
interface DateInputProps {
374
source: string;
375
label?: string | false;
376
validate?: Function | Function[];
377
defaultValue?: Date | string;
378
format?: string;
379
parse?: (value: any) => any;
380
disabled?: boolean;
381
readOnly?: boolean;
382
fullWidth?: boolean;
383
margin?: 'none' | 'dense' | 'normal';
384
variant?: 'standard' | 'outlined' | 'filled';
385
className?: string;
386
sx?: any;
387
}
388
389
const DateInput: React.FC<DateInputProps>;
390
```
391
392
### DateTimeInput
393
394
Combined date and time picker.
395
396
```typescript { .api }
397
import { DateTimeInput } from 'react-admin';
398
399
const DateTimeInput: React.FC<DateInputProps>;
400
```
401
402
### TimeInput
403
404
Time picker input.
405
406
```typescript { .api }
407
import { TimeInput } from 'react-admin';
408
409
const TimeInput: React.FC<DateInputProps>;
410
```
411
412
#### Usage Examples
413
414
```typescript
415
// Date input
416
<DateInput source="publishedAt" label="Published Date" />
417
418
// DateTime input with validation
419
<DateTimeInput
420
source="eventDate"
421
label="Event Date & Time"
422
validate={[required(), minValue(new Date())]}
423
/>
424
425
// Time input
426
<TimeInput source="reminderTime" label="Reminder Time" />
427
```
428
429
## File and Media Inputs
430
431
### FileInput
432
433
File upload input with preview capabilities.
434
435
```typescript { .api }
436
import { FileInput } from 'react-admin';
437
438
interface FileInputProps {
439
source: string;
440
accept?: string;
441
multiple?: boolean;
442
maxSize?: number;
443
minSize?: number;
444
placeholder?: React.ReactNode;
445
children?: React.ReactNode;
446
options?: any;
447
label?: string | false;
448
validate?: Function | Function[];
449
className?: string;
450
sx?: any;
451
}
452
453
const FileInput: React.FC<FileInputProps>;
454
```
455
456
### ImageInput
457
458
Specialized file input for images with preview.
459
460
```typescript { .api }
461
import { ImageInput } from 'react-admin';
462
463
const ImageInput: React.FC<FileInputProps>;
464
```
465
466
#### Usage Examples
467
468
```typescript
469
// Basic file input
470
<FileInput source="document" label="Upload Document">
471
<FileField source="src" title="title" />
472
</FileInput>
473
474
// Image input with preview
475
<ImageInput source="image" label="Product Image" accept="image/*">
476
<ImageField source="src" title="title" />
477
</ImageInput>
478
479
// Multiple file upload
480
<FileInput
481
source="attachments"
482
label="Attachments"
483
multiple
484
accept="application/pdf,image/*"
485
>
486
<FileField source="src" title="title" />
487
</FileInput>
488
```
489
490
## Relationship Inputs
491
492
### ReferenceInput
493
494
Input for selecting related records.
495
496
```typescript { .api }
497
import { ReferenceInput } from 'react-admin';
498
499
interface ReferenceInputProps {
500
source: string;
501
reference: string;
502
children: React.ReactElement;
503
sort?: { field: string; order: 'ASC' | 'DESC' };
504
filter?: any;
505
perPage?: number;
506
enableGetChoices?: Function;
507
label?: string | false;
508
validate?: Function | Function[];
509
className?: string;
510
sx?: any;
511
}
512
513
const ReferenceInput: React.FC<ReferenceInputProps>;
514
```
515
516
#### Usage Example
517
518
```typescript
519
<ReferenceInput source="categoryId" reference="categories">
520
<SelectInput optionText="name" />
521
</ReferenceInput>
522
523
// With autocomplete
524
<ReferenceInput source="authorId" reference="users" sort={{ field: 'name', order: 'ASC' }}>
525
<AutocompleteInput optionText="name" />
526
</ReferenceInput>
527
```
528
529
### ReferenceArrayInput
530
531
Input for selecting multiple related records.
532
533
```typescript { .api }
534
import { ReferenceArrayInput } from 'react-admin';
535
536
interface ReferenceArrayInputProps {
537
source: string;
538
reference: string;
539
children: React.ReactElement;
540
sort?: { field: string; order: 'ASC' | 'DESC' };
541
filter?: any;
542
perPage?: number;
543
label?: string | false;
544
validate?: Function | Function[];
545
className?: string;
546
sx?: any;
547
}
548
549
const ReferenceArrayInput: React.FC<ReferenceArrayInputProps>;
550
```
551
552
#### Usage Example
553
554
```typescript
555
<ReferenceArrayInput source="tagIds" reference="tags">
556
<AutocompleteInput optionText="name" />
557
</ReferenceArrayInput>
558
```
559
560
## Array and Complex Inputs
561
562
### ArrayInput
563
564
Input for editing arrays of objects.
565
566
```typescript { .api }
567
import { ArrayInput } from 'react-admin';
568
569
interface ArrayInputProps {
570
source: string;
571
label?: string | false;
572
validate?: Function | Function[];
573
children: React.ReactElement;
574
className?: string;
575
sx?: any;
576
}
577
578
const ArrayInput: React.FC<ArrayInputProps>;
579
```
580
581
#### Usage Example
582
583
```typescript
584
import { ArrayInput, SimpleFormIterator, TextInput, NumberInput } from 'react-admin';
585
586
<ArrayInput source="items" label="Order Items">
587
<SimpleFormIterator>
588
<TextInput source="name" label="Item Name" />
589
<NumberInput source="quantity" label="Quantity" />
590
<NumberInput source="price" label="Price" />
591
</SimpleFormIterator>
592
</ArrayInput>
593
```
594
595
## Form Hooks
596
597
### useInput
598
599
Access and control individual input state.
600
601
```typescript { .api }
602
import { useInput } from 'react-admin';
603
604
interface UseInputOptions {
605
defaultValue?: any;
606
format?: (value: any) => any;
607
parse?: (value: any) => any;
608
validate?: Function | Function[];
609
onBlur?: Function;
610
onChange?: Function;
611
source: string;
612
}
613
614
interface UseInputResult {
615
field: {
616
name: string;
617
value: any;
618
onChange: (event: any) => void;
619
onBlur: (event: any) => void;
620
};
621
fieldState: {
622
invalid: boolean;
623
isTouched: boolean;
624
isDirty: boolean;
625
error?: any;
626
};
627
formState: {
628
isSubmitted: boolean;
629
isSubmitting: boolean;
630
isValid: boolean;
631
errors: any;
632
};
633
}
634
635
const useInput: (options: UseInputOptions) => UseInputResult;
636
```
637
638
#### Usage Example
639
640
```typescript
641
import { useInput } from 'react-admin';
642
643
const CustomInput = ({ source, label, ...props }) => {
644
const {
645
field,
646
fieldState: { error, invalid, isTouched },
647
formState: { isSubmitted }
648
} = useInput({ source, ...props });
649
650
return (
651
<div>
652
<label>{label}</label>
653
<input {...field} />
654
{((isTouched && invalid) || (isSubmitted && invalid)) && (
655
<span style={{ color: 'red' }}>{error?.message}</span>
656
)}
657
</div>
658
);
659
};
660
```
661
662
### useForm
663
664
Access form state and methods.
665
666
```typescript { .api }
667
import { useForm } from 'react-admin';
668
669
const useForm: () => {
670
getValues: (names?: string | string[]) => any;
671
setValue: (name: string, value: any, options?: any) => void;
672
reset: (values?: any) => void;
673
watch: (name?: string | string[], defaultValue?: any) => any;
674
formState: FormState;
675
control: Control;
676
register: Function;
677
handleSubmit: Function;
678
clearErrors: Function;
679
setError: Function;
680
trigger: Function;
681
};
682
```
683
684
## Validation
685
686
React Admin provides comprehensive validation capabilities.
687
688
### Built-in Validators
689
690
```typescript { .api }
691
import {
692
required,
693
minLength,
694
maxLength,
695
minValue,
696
maxValue,
697
number,
698
regex,
699
email,
700
choices
701
} from 'react-admin';
702
703
// Validation function types
704
type ValidatorFunction = (value: any, allValues?: any, props?: any) => string | undefined;
705
706
const required: (message?: string) => ValidatorFunction;
707
const minLength: (min: number, message?: string) => ValidatorFunction;
708
const maxLength: (max: number, message?: string) => ValidatorFunction;
709
const minValue: (min: number, message?: string) => ValidatorFunction;
710
const maxValue: (max: number, message?: string) => ValidatorFunction;
711
const number: (message?: string) => ValidatorFunction;
712
const regex: (pattern: RegExp, message?: string) => ValidatorFunction;
713
const email: (message?: string) => ValidatorFunction;
714
const choices: (list: any[], message?: string) => ValidatorFunction;
715
```
716
717
### Validation Examples
718
719
```typescript
720
import { required, minLength, maxLength, email, minValue } from 'react-admin';
721
722
// Single validator
723
<TextInput source="title" validate={required()} />
724
725
// Multiple validators
726
<TextInput
727
source="description"
728
validate={[required(), minLength(10), maxLength(500)]}
729
/>
730
731
// Email validation
732
<TextInput source="email" validate={[required(), email()]} />
733
734
// Number validation
735
<NumberInput
736
source="price"
737
validate={[required(), minValue(0)]}
738
/>
739
740
// Custom validation
741
<TextInput
742
source="username"
743
validate={(value) => {
744
if (!value) return 'Username is required';
745
if (value.length < 3) return 'Username must be at least 3 characters';
746
if (!/^[a-zA-Z0-9_]+$/.test(value)) return 'Username can only contain letters, numbers, and underscores';
747
return undefined;
748
}}
749
/>
750
```
751
752
### Async Validation
753
754
```typescript
755
const asyncValidate = async (value) => {
756
if (!value) return 'Required';
757
758
const response = await fetch(`/api/check-username?username=${value}`);
759
const result = await response.json();
760
761
if (!result.available) {
762
return 'Username is already taken';
763
}
764
765
return undefined;
766
};
767
768
<TextInput source="username" validate={asyncValidate} />
769
```
770
771
## Advanced Form Features
772
773
### FormDataConsumer
774
775
Access and react to form data changes.
776
777
```typescript { .api }
778
import { FormDataConsumer } from 'react-admin';
779
780
interface FormDataConsumerProps {
781
children: (formDataConsumerProps: FormDataConsumerRenderParams) => React.ReactNode;
782
}
783
784
interface FormDataConsumerRenderParams {
785
formData: any;
786
scopedFormData?: any;
787
getSource?: (source: string) => string;
788
}
789
790
const FormDataConsumer: React.FC<FormDataConsumerProps>;
791
```
792
793
#### Usage Example
794
795
```typescript
796
import { FormDataConsumer, SelectInput, TextInput } from 'react-admin';
797
798
<FormDataConsumer>
799
{({ formData, ...rest }) => (
800
<>
801
<SelectInput source="type" choices={typeChoices} {...rest} />
802
{formData.type === 'book' && (
803
<TextInput source="isbn" label="ISBN" {...rest} />
804
)}
805
{formData.type === 'movie' && (
806
<TextInput source="director" label="Director" {...rest} />
807
)}
808
</>
809
)}
810
</FormDataConsumer>
811
```
812
813
### Conditional Fields
814
815
```typescript
816
import { FormDataConsumer, BooleanInput, TextInput } from 'react-admin';
817
818
const ConditionalFieldsExample = () => (
819
<>
820
<BooleanInput source="hasDiscount" label="Has Discount" />
821
<FormDataConsumer>
822
{({ formData }) =>
823
formData.hasDiscount && (
824
<NumberInput
825
source="discountPercentage"
826
label="Discount %"
827
min={0}
828
max={100}
829
/>
830
)
831
}
832
</FormDataConsumer>
833
</>
834
);
835
```
836
837
### Form Sections and Layouts
838
839
```typescript
840
import {
841
Form,
842
TextInput,
843
NumberInput,
844
TabbedForm,
845
FormTab,
846
Toolbar,
847
SaveButton,
848
DeleteButton
849
} from 'react-admin';
850
851
const ProductForm = () => (
852
<TabbedForm>
853
<FormTab label="General">
854
<TextInput source="name" label="Product Name" />
855
<NumberInput source="price" label="Price" />
856
<TextInput source="description" multiline rows={4} />
857
</FormTab>
858
859
<FormTab label="Inventory">
860
<NumberInput source="stock" label="Stock Quantity" />
861
<NumberInput source="minStock" label="Minimum Stock" />
862
<BooleanInput source="trackInventory" label="Track Inventory" />
863
</FormTab>
864
865
<FormTab label="SEO">
866
<TextInput source="metaTitle" label="Meta Title" />
867
<TextInput source="metaDescription" label="Meta Description" multiline />
868
<TextInput source="slug" label="URL Slug" />
869
</FormTab>
870
871
<Toolbar>
872
<SaveButton />
873
<DeleteButton />
874
</Toolbar>
875
</TabbedForm>
876
);
877
```
878
879
React Admin's form system provides powerful, flexible form handling with rich validation, sophisticated input components, and excellent developer experience for building complex data entry interfaces.