0
# Form Controls
1
2
Core form elements providing accessible, headless components for user input including buttons, inputs, switches, sliders, and form control context management.
3
4
## Capabilities
5
6
### Button Component
7
8
Headless button component with built-in accessibility features and polymorphic support.
9
10
```typescript { .api }
11
/**
12
* Headless button component with accessibility and polymorphic support
13
* @param props - Button properties including styling slots and behavior options
14
* @returns Button element with proper accessibility attributes
15
*/
16
function Button<RootComponentType extends React.ElementType = "button">(
17
props: ButtonProps<RootComponentType>
18
): JSX.Element;
19
20
interface ButtonProps<RootComponentType extends React.ElementType = "button">
21
extends PolymorphicProps<ButtonTypeMap, RootComponentType> {
22
/** Ref for imperative actions like focusVisible() */
23
action?: React.Ref<ButtonActions>;
24
/** Button content */
25
children?: React.ReactNode;
26
/** Props for customizing button slots */
27
slotProps?: {
28
root?: SlotComponentProps<ButtonSlots["root"], {}, ButtonOwnerState>;
29
};
30
/** Components used for button slots */
31
slots?: ButtonSlots;
32
/** HTML element name for root (default: 'button') */
33
rootElementName?: keyof HTMLElementTagNameMap;
34
/** Whether button is disabled */
35
disabled?: boolean;
36
/** Whether button is focusable when disabled */
37
focusableWhenDisabled?: boolean;
38
/** Href for link-style buttons */
39
href?: string;
40
/** Tab index override */
41
tabIndex?: number;
42
/** Router link destination */
43
to?: string;
44
/** Button type attribute */
45
type?: "button" | "submit" | "reset";
46
}
47
48
interface ButtonSlots {
49
/** Root button element */
50
root?: React.ElementType;
51
}
52
53
interface ButtonActions {
54
/** Focus the button and show focus visible indicator */
55
focusVisible(): void;
56
}
57
58
interface ButtonOwnerState {
59
active: boolean;
60
disabled: boolean;
61
focusVisible: boolean;
62
}
63
```
64
65
**Usage Examples:**
66
67
```typescript
68
import { Button } from "@mui/base/Button";
69
70
// Basic button
71
<Button onClick={() => console.log("clicked")}>
72
Click me
73
</Button>
74
75
// Custom styled button
76
<Button
77
className="btn btn-primary"
78
slotProps={{
79
root: { className: "custom-root" }
80
}}
81
>
82
Styled Button
83
</Button>
84
85
// Link-style button
86
<Button href="/dashboard" component="a">
87
Go to Dashboard
88
</Button>
89
90
// Disabled but focusable button
91
<Button disabled focusableWhenDisabled>
92
Disabled but Focusable
93
</Button>
94
```
95
96
**Button Classes:**
97
98
```typescript { .api }
99
// CSS classes for Button component styling
100
interface ButtonClasses {
101
/** Class name applied to the root element */
102
root: string;
103
/** State class applied if active={true} */
104
active: string;
105
/** State class applied if disabled={true} */
106
disabled: string;
107
/** State class applied if focusVisible={true} */
108
focusVisible: string;
109
}
110
111
// Button classes object
112
declare const buttonClasses: ButtonClasses;
113
114
// Utility function for Button class generation
115
function getButtonUtilityClass(slot: string): string;
116
```
117
118
### Input Component
119
120
Headless input component with form control integration and validation support.
121
122
```typescript { .api }
123
/**
124
* Headless input component with form control integration
125
* @param props - Input properties including value, validation, and styling
126
* @returns Input element with proper form control integration
127
*/
128
function Input<RootComponentType extends React.ElementType = "div">(
129
props: InputProps<RootComponentType>
130
): JSX.Element;
131
132
interface InputProps<RootComponentType extends React.ElementType = "div">
133
extends PolymorphicProps<InputTypeMap, RootComponentType> {
134
/** Default input value */
135
defaultValue?: unknown;
136
/** Whether input is disabled */
137
disabled?: boolean;
138
/** Whether input has validation error */
139
error?: boolean;
140
/** Change event handler */
141
onChange?: React.ChangeEventHandler<HTMLInputElement>;
142
/** Whether input is required */
143
required?: boolean;
144
/** Current input value */
145
value?: unknown;
146
/** Props for customizing input slots */
147
slotProps?: {
148
root?: SlotComponentProps<InputSlots["root"], {}, InputOwnerState>;
149
input?: SlotComponentProps<InputSlots["input"], {}, InputOwnerState>;
150
};
151
/** Components used for input slots */
152
slots?: InputSlots;
153
/** Input placeholder text */
154
placeholder?: string;
155
/** Input type attribute */
156
type?: string;
157
/** Input name attribute */
158
name?: string;
159
/** Input id attribute */
160
id?: string;
161
}
162
163
interface InputSlots {
164
/** Root container element */
165
root?: React.ElementType;
166
/** Input element */
167
input?: React.ElementType;
168
}
169
170
interface InputOwnerState {
171
disabled: boolean;
172
error: boolean;
173
focused: boolean;
174
required: boolean;
175
value: unknown;
176
}
177
```
178
179
**Usage Examples:**
180
181
```typescript
182
import { Input, FormControl } from "@mui/base";
183
184
// Basic input
185
<Input
186
placeholder="Enter your name"
187
onChange={(e) => setName(e.target.value)}
188
/>
189
190
// Input with form control
191
<FormControl error={hasError}>
192
<Input
193
value={email}
194
onChange={(e) => setEmail(e.target.value)}
195
type="email"
196
required
197
/>
198
</FormControl>
199
200
// Custom styled input
201
<Input
202
slotProps={{
203
root: { className: "input-wrapper" },
204
input: { className: "input-field" }
205
}}
206
/>
207
```
208
209
### Switch Component
210
211
Toggle switch component for boolean values with accessibility support.
212
213
```typescript { .api }
214
/**
215
* Toggle switch component for boolean values
216
* @param props - Switch properties including checked state and styling
217
* @returns Switch element with proper accessibility attributes
218
*/
219
function Switch<RootComponentType extends React.ElementType = "span">(
220
props: SwitchProps<RootComponentType>
221
): JSX.Element;
222
223
interface SwitchProps<RootComponentType extends React.ElementType = "span">
224
extends PolymorphicProps<SwitchTypeMap, RootComponentType> {
225
/** Whether switch is checked */
226
checked?: boolean;
227
/** Default checked state */
228
defaultChecked?: boolean;
229
/** Whether switch is disabled */
230
disabled?: boolean;
231
/** Change event handler */
232
onChange?: React.ChangeEventHandler<HTMLInputElement>;
233
/** Whether switch is read-only */
234
readOnly?: boolean;
235
/** Whether switch is required */
236
required?: boolean;
237
/** Props for customizing switch slots */
238
slotProps?: {
239
root?: SlotComponentProps<SwitchSlots["root"], {}, SwitchOwnerState>;
240
thumb?: SlotComponentProps<SwitchSlots["thumb"], {}, SwitchOwnerState>;
241
input?: SlotComponentProps<SwitchSlots["input"], {}, SwitchOwnerState>;
242
track?: SlotComponentProps<SwitchSlots["track"], {}, SwitchOwnerState>;
243
};
244
/** Components used for switch slots */
245
slots?: SwitchSlots;
246
}
247
248
interface SwitchSlots {
249
/** Root container element */
250
root?: React.ElementType;
251
/** Switch thumb element */
252
thumb?: React.ElementType;
253
/** Hidden input element */
254
input?: React.ElementType;
255
/** Switch track element */
256
track?: React.ElementType;
257
}
258
259
interface SwitchOwnerState {
260
checked: boolean;
261
disabled: boolean;
262
focusVisible: boolean;
263
readOnly: boolean;
264
}
265
```
266
267
### Slider Component
268
269
Range slider component for numeric value selection with marks and accessibility.
270
271
```typescript { .api }
272
/**
273
* Range slider component for numeric value selection
274
* @param props - Slider properties including value range and styling
275
* @returns Slider element with proper accessibility and keyboard support
276
*/
277
function Slider<RootComponentType extends React.ElementType = "span">(
278
props: SliderProps<RootComponentType>
279
): JSX.Element;
280
281
interface SliderProps<RootComponentType extends React.ElementType = "span">
282
extends PolymorphicProps<SliderTypeMap, RootComponentType> {
283
/** Current slider value or array of values */
284
value?: number | number[];
285
/** Default slider value */
286
defaultValue?: number | number[];
287
/** Minimum slider value */
288
min?: number;
289
/** Maximum slider value */
290
max?: number;
291
/** Step increment */
292
step?: number | null;
293
/** Whether slider is disabled */
294
disabled?: boolean;
295
/** Marks on the slider */
296
marks?: boolean | SliderMark[];
297
/** Change event handler */
298
onChange?: (event: Event, value: number | number[]) => void;
299
/** Change committed event handler */
300
onChangeCommitted?: (event: React.SyntheticEvent | Event, value: number | number[]) => void;
301
/** Props for customizing slider slots */
302
slotProps?: {
303
root?: SlotComponentProps<SliderSlots["root"], {}, SliderOwnerState>;
304
rail?: SlotComponentProps<SliderSlots["rail"], {}, SliderOwnerState>;
305
track?: SlotComponentProps<SliderSlots["track"], {}, SliderOwnerState>;
306
thumb?: SlotComponentProps<SliderSlots["thumb"], {}, SliderOwnerState>;
307
mark?: SlotComponentProps<SliderSlots["mark"], {}, SliderOwnerState>;
308
markLabel?: SlotComponentProps<SliderSlots["markLabel"], {}, SliderOwnerState>;
309
valueLabel?: SlotComponentProps<SliderSlots["valueLabel"], {}, SliderOwnerState>;
310
input?: SlotComponentProps<SliderSlots["input"], {}, SliderOwnerState>;
311
};
312
/** Components used for slider slots */
313
slots?: SliderSlots;
314
}
315
316
interface SliderSlots {
317
root?: React.ElementType;
318
rail?: React.ElementType;
319
track?: React.ElementType;
320
thumb?: React.ElementType;
321
mark?: React.ElementType;
322
markLabel?: React.ElementType;
323
valueLabel?: React.ElementType;
324
input?: React.ElementType;
325
}
326
327
interface SliderMark {
328
value: number;
329
label?: React.ReactNode;
330
}
331
```
332
333
### Badge Component
334
335
Badge component for status indicators and counts.
336
337
```typescript { .api }
338
/**
339
* Badge component for status indicators and counts
340
* @param props - Badge properties including content and visibility
341
* @returns Badge element positioned relative to children
342
*/
343
function Badge<RootComponentType extends React.ElementType = "span">(
344
props: BadgeProps<RootComponentType>
345
): JSX.Element;
346
347
interface BadgeProps<RootComponentType extends React.ElementType = "span">
348
extends PolymorphicProps<BadgeTypeMap, RootComponentType> {
349
/** Content rendered within the badge */
350
badgeContent?: React.ReactNode;
351
/** The badge will be added relative to this node */
352
children?: React.ReactNode;
353
/** If true, the badge is invisible */
354
invisible?: boolean;
355
/** Max count to show (default: 99) */
356
max?: number;
357
/** Controls whether badge is hidden when badgeContent is zero */
358
showZero?: boolean;
359
/** Props for customizing badge slots */
360
slotProps?: {
361
root?: SlotComponentProps<BadgeSlots["root"], {}, BadgeOwnerState>;
362
badge?: SlotComponentProps<BadgeSlots["badge"], {}, BadgeOwnerState>;
363
};
364
/** Components used for badge slots */
365
slots?: BadgeSlots;
366
}
367
368
interface BadgeSlots {
369
/** Root container element */
370
root?: React.ElementType;
371
/** Badge indicator element */
372
badge?: React.ElementType;
373
}
374
375
interface BadgeOwnerState {
376
badgeContent: React.ReactNode;
377
invisible: boolean;
378
max: number;
379
showZero: boolean;
380
}
381
```
382
383
### FormControl Component
384
385
Provides form control context to child components for coordinated state management.
386
387
```typescript { .api }
388
/**
389
* Form control context provider for coordinated form state
390
* @param props - Form control properties including value and validation state
391
* @returns Context provider for form control state
392
*/
393
function FormControl<RootComponentType extends React.ElementType = "div">(
394
props: FormControlProps<RootComponentType>
395
): JSX.Element;
396
397
interface FormControlProps<RootComponentType extends React.ElementType = "div">
398
extends PolymorphicProps<FormControlTypeMap, RootComponentType> {
399
/** Default form control value */
400
defaultValue?: unknown;
401
/** Whether form control is disabled */
402
disabled?: boolean;
403
/** Whether form control is in error state */
404
error?: boolean;
405
/** Change handler for form control */
406
onChange?: (event: React.SyntheticEvent) => void;
407
/** Whether form control is required */
408
required?: boolean;
409
/** Current form control value */
410
value?: unknown;
411
/** Form control children */
412
children?: React.ReactNode;
413
}
414
415
// Hook for accessing form control context
416
function useFormControlContext(): FormControlState | undefined;
417
418
interface FormControlState {
419
disabled: boolean;
420
error: boolean;
421
required: boolean;
422
value: unknown;
423
onChange: (event: React.SyntheticEvent) => void;
424
}
425
```
426
427
### NumberInput Component (Unstable)
428
429
Specialized number input with increment/decrement stepper controls.
430
431
```typescript { .api }
432
/**
433
* Number input component with increment/decrement controls
434
* @param props - Number input properties including min/max bounds and step
435
* @returns Number input element with stepper controls
436
*/
437
function Unstable_NumberInput<RootComponentType extends React.ElementType = "div">(
438
props: NumberInputProps<RootComponentType>
439
): JSX.Element;
440
441
interface NumberInputProps<RootComponentType extends React.ElementType = "div">
442
extends PolymorphicProps<NumberInputTypeMap, RootComponentType> {
443
/** Current number value */
444
value?: number;
445
/** Default number value */
446
defaultValue?: number;
447
/** Minimum allowed value */
448
min?: number;
449
/** Maximum allowed value */
450
max?: number;
451
/** Step increment for stepper controls */
452
step?: number;
453
/** Whether input is disabled */
454
disabled?: boolean;
455
/** Whether input has validation error */
456
error?: boolean;
457
/** Whether input is required */
458
required?: boolean;
459
/** Change event handler */
460
onChange?: (event: React.FocusEvent<HTMLInputElement> | React.PointerEvent | React.KeyboardEvent, value: number | null) => void;
461
/** Props for customizing number input slots */
462
slotProps?: {
463
root?: SlotComponentProps<NumberInputSlots["root"], {}, NumberInputOwnerState>;
464
input?: SlotComponentProps<NumberInputSlots["input"], {}, NumberInputOwnerState>;
465
incrementButton?: SlotComponentProps<NumberInputSlots["incrementButton"], {}, NumberInputOwnerState>;
466
decrementButton?: SlotComponentProps<NumberInputSlots["decrementButton"], {}, NumberInputOwnerState>;
467
};
468
/** Components used for number input slots */
469
slots?: NumberInputSlots;
470
}
471
472
interface NumberInputSlots {
473
root?: React.ElementType;
474
input?: React.ElementType;
475
incrementButton?: React.ElementType;
476
decrementButton?: React.ElementType;
477
}
478
```
479
480
## Related Hooks
481
482
```typescript { .api }
483
// Button behavior hook
484
function useButton(parameters: UseButtonParameters): UseButtonReturnValue;
485
486
// Input behavior hook
487
function useInput(parameters: UseInputParameters): UseInputReturnValue;
488
489
// Switch behavior hook
490
function useSwitch(parameters: UseSwitchParameters): UseSwitchReturnValue;
491
492
// Slider behavior hook
493
function useSlider(parameters: UseSliderParameters): UseSliderReturnValue;
494
495
// Badge display logic hook
496
function useBadge(parameters: UseBadgeParameters): UseBadgeReturnValue;
497
498
// Number input behavior hook
499
function unstable_useNumberInput(parameters: UseNumberInputParameters): UseNumberInputReturnValue;
500
```