0
# Form Components
1
2
Complete form controls including text fields, selects, checkboxes, and form validation with Material Design styling.
3
4
## Capabilities
5
6
### TextField
7
8
Complete text field component with label, input, helper text, and error states.
9
10
```typescript { .api }
11
/**
12
* Complete text field with label, input and helper text
13
* @param props - TextField configuration
14
* @returns TextField component
15
*/
16
function TextField(props: TextFieldProps): JSX.Element;
17
18
interface TextFieldProps extends CommonProps {
19
/** The variant to use */
20
variant?: 'filled' | 'outlined' | 'standard';
21
/** The size of the component */
22
size?: 'small' | 'medium';
23
/** The color of the component */
24
color?: 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning';
25
/** If true, the component takes up the full width of its container */
26
fullWidth?: boolean;
27
/** The label content */
28
label?: React.ReactNode;
29
/** The helper text content */
30
helperText?: React.ReactNode;
31
/** If true, the label is displayed in an error state */
32
error?: boolean;
33
/** If true, the component is disabled */
34
disabled?: boolean;
35
/** If true, the Input will be required */
36
required?: boolean;
37
/** The default value */
38
defaultValue?: unknown;
39
/** The value of the component */
40
value?: unknown;
41
/** Callback fired when the value is changed */
42
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
43
/** Name attribute of the input element */
44
name?: string;
45
/** The short hint displayed in the input before the user enters a value */
46
placeholder?: string;
47
/** Type of the input element */
48
type?: string;
49
/** If true, the component will be displayed in focused state */
50
autoFocus?: boolean;
51
/** If true, the component displays a multiline input */
52
multiline?: boolean;
53
/** Maximum number of rows to display when multiline option is set to true */
54
maxRows?: number;
55
/** Minimum number of rows to display when multiline option is set to true */
56
minRows?: number;
57
/** Number of rows to display when multiline option is set to true */
58
rows?: number;
59
/** Render a Select element while passing the Input element to Select as input parameter */
60
select?: boolean;
61
/** The option elements to populate the select with */
62
children?: React.ReactNode;
63
/** Props applied to the Input element */
64
InputProps?: Partial<OutlinedInputProps>;
65
/** Props applied to the InputLabel element */
66
InputLabelProps?: Partial<InputLabelProps>;
67
/** Props applied to the FormHelperText element */
68
FormHelperTextProps?: Partial<FormHelperTextProps>;
69
}
70
```
71
72
**Usage Examples:**
73
74
```typescript
75
import { TextField, MenuItem } from "@mui/material";
76
77
// Basic text field
78
<TextField
79
label="Email"
80
variant="outlined"
81
type="email"
82
fullWidth
83
required
84
/>
85
86
// Text field with helper text and error
87
<TextField
88
label="Password"
89
type="password"
90
error
91
helperText="Password must be at least 8 characters"
92
fullWidth
93
/>
94
95
// Multiline text field
96
<TextField
97
label="Description"
98
multiline
99
rows={4}
100
fullWidth
101
placeholder="Enter your description here..."
102
/>
103
104
// Select field
105
<TextField
106
select
107
label="Country"
108
value={country}
109
onChange={handleChange}
110
fullWidth
111
>
112
<MenuItem value="us">United States</MenuItem>
113
<MenuItem value="ca">Canada</MenuItem>
114
<MenuItem value="uk">United Kingdom</MenuItem>
115
</TextField>
116
```
117
118
### FormControl
119
120
Provides context such as filled/focused/error/required for form inputs.
121
122
```typescript { .api }
123
/**
124
* Form control wrapper providing context
125
* @param props - FormControl configuration
126
* @returns FormControl component
127
*/
128
function FormControl(props: FormControlProps): JSX.Element;
129
130
interface FormControlProps extends CommonProps {
131
/** The color of the component */
132
color?: 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning';
133
/** If true, the component is disabled */
134
disabled?: boolean;
135
/** If true, the label should be displayed in an error state */
136
error?: boolean;
137
/** If true, the component will take up the full width of its container */
138
fullWidth?: boolean;
139
/** If true, the component is focused */
140
focused?: boolean;
141
/** If true, the label is hidden */
142
hiddenLabel?: boolean;
143
/** The margin to apply to the component */
144
margin?: 'dense' | 'normal' | 'none';
145
/** If true, the label will indicate that the input is required */
146
required?: boolean;
147
/** The size of the component */
148
size?: 'small' | 'medium';
149
/** The variant to use */
150
variant?: 'standard' | 'outlined' | 'filled';
151
/** The component used for the root node */
152
component?: React.ElementType;
153
children?: React.ReactNode;
154
}
155
```
156
157
### FormControlLabel
158
159
Drop-in replacement for labels with built-in FormControl context.
160
161
```typescript { .api }
162
/**
163
* Label with FormControl context
164
* @param props - FormControlLabel configuration
165
* @returns FormControlLabel component
166
*/
167
function FormControlLabel(props: FormControlLabelProps): JSX.Element;
168
169
interface FormControlLabelProps extends CommonProps {
170
/** A control element. For instance, it can be a Radio, a Switch or a Checkbox */
171
control: React.ReactElement;
172
/** The text to be used in an enclosing label element */
173
label: React.ReactNode;
174
/** The position of the label */
175
labelPlacement?: 'end' | 'start' | 'top' | 'bottom';
176
/** If true, the component appears selected */
177
checked?: boolean;
178
/** If true, the control is disabled */
179
disabled?: boolean;
180
/** Name attribute of the input element */
181
name?: string;
182
/** Callback fired when the state is changed */
183
onChange?: (event: React.SyntheticEvent, checked: boolean) => void;
184
/** The value of the component */
185
value?: unknown;
186
/** If true, the input element is required */
187
required?: boolean;
188
}
189
```
190
191
### Checkbox
192
193
Checkbox input component with customizable states and styling.
194
195
```typescript { .api }
196
/**
197
* Checkbox input component
198
* @param props - Checkbox configuration
199
* @returns Checkbox component
200
*/
201
function Checkbox(props: CheckboxProps): JSX.Element;
202
203
interface CheckboxProps extends CommonProps {
204
/** If true, the component is checked */
205
checked?: boolean;
206
/** The icon to display when the component is checked */
207
checkedIcon?: React.ReactNode;
208
/** The color of the component */
209
color?: 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' | 'default';
210
/** The default checked state */
211
defaultChecked?: boolean;
212
/** If true, the component is disabled */
213
disabled?: boolean;
214
/** If true, the ripple effect is disabled */
215
disableRipple?: boolean;
216
/** The icon to display when the component is unchecked */
217
icon?: React.ReactNode;
218
/** If true, the component appears indeterminate */
219
indeterminate?: boolean;
220
/** The icon to display when the component is indeterminate */
221
indeterminateIcon?: React.ReactNode;
222
/** Attributes applied to the input element */
223
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
224
/** Pass a ref to the input element */
225
inputRef?: React.Ref<HTMLInputElement>;
226
/** Callback fired when the state is changed */
227
onChange?: (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => void;
228
/** If true, the input element is required */
229
required?: boolean;
230
/** The size of the component */
231
size?: 'small' | 'medium';
232
/** The value of the component */
233
value?: unknown;
234
}
235
```
236
237
**Usage Examples:**
238
239
```typescript
240
import { Checkbox, FormControlLabel, FormGroup } from "@mui/material";
241
242
// Basic checkbox
243
<FormControlLabel
244
control={<Checkbox />}
245
label="Accept terms and conditions"
246
/>
247
248
// Controlled checkbox
249
<FormControlLabel
250
control={
251
<Checkbox
252
checked={checked}
253
onChange={handleChange}
254
color="primary"
255
/>
256
}
257
label="Enable notifications"
258
/>
259
260
// Checkbox group
261
<FormGroup>
262
<FormControlLabel control={<Checkbox />} label="Option 1" />
263
<FormControlLabel control={<Checkbox />} label="Option 2" />
264
<FormControlLabel control={<Checkbox />} label="Option 3" />
265
</FormGroup>
266
```
267
268
### Radio and RadioGroup
269
270
Radio button components for single selection from multiple options.
271
272
```typescript { .api }
273
/**
274
* Radio button input component
275
* @param props - Radio configuration
276
* @returns Radio component
277
*/
278
function Radio(props: RadioProps): JSX.Element;
279
280
/**
281
* Groups radio buttons and manages selection
282
* @param props - RadioGroup configuration
283
* @returns RadioGroup component
284
*/
285
function RadioGroup(props: RadioGroupProps): JSX.Element;
286
287
interface RadioProps extends CommonProps {
288
/** If true, the component is checked */
289
checked?: boolean;
290
/** The icon to display when the component is checked */
291
checkedIcon?: React.ReactNode;
292
/** The color of the component */
293
color?: 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' | 'default';
294
/** If true, the component is disabled */
295
disabled?: boolean;
296
/** If true, the ripple effect is disabled */
297
disableRipple?: boolean;
298
/** The icon to display when the component is unchecked */
299
icon?: React.ReactNode;
300
/** Attributes applied to the input element */
301
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
302
/** Name attribute of the input element */
303
name?: string;
304
/** Callback fired when the state is changed */
305
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
306
/** If true, the input element is required */
307
required?: boolean;
308
/** The size of the component */
309
size?: 'small' | 'medium';
310
/** The value of the component */
311
value?: unknown;
312
}
313
314
interface RadioGroupProps extends CommonProps {
315
/** The default selected value */
316
defaultValue?: unknown;
317
/** The name used to reference the value of the control */
318
name?: string;
319
/** Callback fired when a radio button is selected */
320
onChange?: (event: React.ChangeEvent<HTMLInputElement>, value: string) => void;
321
/** Display group of radio buttons in a row */
322
row?: boolean;
323
/** Value of the selected radio button */
324
value?: unknown;
325
children?: React.ReactNode;
326
}
327
```
328
329
**Usage Examples:**
330
331
```typescript
332
import { Radio, RadioGroup, FormControlLabel, FormControl, FormLabel } from "@mui/material";
333
334
// Radio group
335
<FormControl component="fieldset">
336
<FormLabel component="legend">Gender</FormLabel>
337
<RadioGroup
338
aria-label="gender"
339
name="gender"
340
value={value}
341
onChange={handleChange}
342
>
343
<FormControlLabel value="female" control={<Radio />} label="Female" />
344
<FormControlLabel value="male" control={<Radio />} label="Male" />
345
<FormControlLabel value="other" control={<Radio />} label="Other" />
346
</RadioGroup>
347
</FormControl>
348
```
349
350
### Select
351
352
Select dropdown component for choosing from multiple options.
353
354
```typescript { .api }
355
/**
356
* Select dropdown component
357
* @param props - Select configuration
358
* @returns Select component
359
*/
360
function Select<T>(props: SelectProps<T>): JSX.Element;
361
362
interface SelectProps<T> extends CommonProps {
363
/** If true, the width of the popover will automatically be set according to the items inside the menu */
364
autoWidth?: boolean;
365
/** The default selected value */
366
defaultValue?: T;
367
/** If true, a value is displayed even if no items are selected */
368
displayEmpty?: boolean;
369
/** The icon that displays the arrow */
370
IconComponent?: React.ComponentType;
371
/** The input component */
372
input?: React.ReactElement;
373
/** Attributes applied to the input element */
374
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
375
/** The label element */
376
label?: React.ReactNode;
377
/** The ID of an element that acts as an additional label */
378
labelId?: string;
379
/** Props applied to the Menu element */
380
MenuProps?: Partial<MenuProps>;
381
/** If true, value must be an array and the menu will support multiple selections */
382
multiple?: boolean;
383
/** If true, the component uses a native select element */
384
native?: boolean;
385
/** Callback fired when a menu item is selected */
386
onChange?: (event: SelectChangeEvent<T>, child: React.ReactNode) => void;
387
/** Callback fired when the component requests to be closed */
388
onClose?: (event: React.SyntheticEvent) => void;
389
/** Callback fired when the component requests to be opened */
390
onOpen?: (event: React.SyntheticEvent) => void;
391
/** If true, the component is shown */
392
open?: boolean;
393
/** Render the selected value */
394
renderValue?: (value: T) => React.ReactNode;
395
/** Props applied to the clickable div element */
396
SelectDisplayProps?: React.HTMLAttributes<HTMLDivElement>;
397
/** The input value */
398
value?: T;
399
/** The variant to use */
400
variant?: 'standard' | 'outlined' | 'filled';
401
children?: React.ReactNode;
402
}
403
```
404
405
**Usage Examples:**
406
407
```typescript
408
import { Select, MenuItem, FormControl, InputLabel } from "@mui/material";
409
410
// Basic select
411
<FormControl fullWidth>
412
<InputLabel>Age</InputLabel>
413
<Select
414
value={age}
415
label="Age"
416
onChange={handleChange}
417
>
418
<MenuItem value={10}>Ten</MenuItem>
419
<MenuItem value={20}>Twenty</MenuItem>
420
<MenuItem value={30}>Thirty</MenuItem>
421
</Select>
422
</FormControl>
423
424
// Multiple select
425
<Select
426
multiple
427
value={selectedItems}
428
onChange={handleChange}
429
renderValue={(selected) => selected.join(', ')}
430
>
431
<MenuItem value="option1">Option 1</MenuItem>
432
<MenuItem value="option2">Option 2</MenuItem>
433
<MenuItem value="option3">Option 3</MenuItem>
434
</Select>
435
```
436
437
## Form Validation Pattern
438
439
```typescript
440
import React, { useState } from "react";
441
import {
442
TextField,
443
Button,
444
FormControl,
445
FormHelperText,
446
Box
447
} from "@mui/material";
448
449
interface FormData {
450
email: string;
451
password: string;
452
confirmPassword: string;
453
}
454
455
interface FormErrors {
456
email?: string;
457
password?: string;
458
confirmPassword?: string;
459
}
460
461
function SignupForm() {
462
const [formData, setFormData] = useState<FormData>({
463
email: "",
464
password: "",
465
confirmPassword: ""
466
});
467
const [errors, setErrors] = useState<FormErrors>({});
468
469
const validateForm = (): boolean => {
470
const newErrors: FormErrors = {};
471
472
if (!formData.email.includes("@")) {
473
newErrors.email = "Please enter a valid email address";
474
}
475
476
if (formData.password.length < 8) {
477
newErrors.password = "Password must be at least 8 characters";
478
}
479
480
if (formData.password !== formData.confirmPassword) {
481
newErrors.confirmPassword = "Passwords do not match";
482
}
483
484
setErrors(newErrors);
485
return Object.keys(newErrors).length === 0;
486
};
487
488
const handleSubmit = (event: React.FormEvent) => {
489
event.preventDefault();
490
if (validateForm()) {
491
// Submit form
492
console.log("Form submitted:", formData);
493
}
494
};
495
496
const handleChange = (field: keyof FormData) =>
497
(event: React.ChangeEvent<HTMLInputElement>) => {
498
setFormData(prev => ({
499
...prev,
500
[field]: event.target.value
501
}));
502
// Clear error when user starts typing
503
if (errors[field]) {
504
setErrors(prev => ({
505
...prev,
506
[field]: undefined
507
}));
508
}
509
};
510
511
return (
512
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
513
<TextField
514
margin="normal"
515
required
516
fullWidth
517
label="Email Address"
518
type="email"
519
value={formData.email}
520
onChange={handleChange('email')}
521
error={!!errors.email}
522
helperText={errors.email}
523
/>
524
525
<TextField
526
margin="normal"
527
required
528
fullWidth
529
label="Password"
530
type="password"
531
value={formData.password}
532
onChange={handleChange('password')}
533
error={!!errors.password}
534
helperText={errors.password}
535
/>
536
537
<TextField
538
margin="normal"
539
required
540
fullWidth
541
label="Confirm Password"
542
type="password"
543
value={formData.confirmPassword}
544
onChange={handleChange('confirmPassword')}
545
error={!!errors.confirmPassword}
546
helperText={errors.confirmPassword}
547
/>
548
549
<Button
550
type="submit"
551
fullWidth
552
variant="contained"
553
sx={{ mt: 3, mb: 2 }}
554
>
555
Sign Up
556
</Button>
557
</Box>
558
);
559
}
560
```