0
# Input Components
1
2
NextUI provides a comprehensive set of form input components with built-in validation, accessibility support, and consistent styling across different input types.
3
4
## Capabilities
5
6
### Input
7
8
A versatile text input component with support for labels, validation, helper text, and various visual states.
9
10
```typescript { .api }
11
interface InputProps {
12
/** Input content and elements */
13
children?: React.ReactNode;
14
/** Input label */
15
label?: React.ReactNode;
16
/** Current input value */
17
value?: string;
18
/** Default value for uncontrolled mode */
19
defaultValue?: string;
20
/** Placeholder text */
21
placeholder?: string;
22
/** Helper description text */
23
description?: React.ReactNode;
24
/** Error message content */
25
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
26
/** Validation function */
27
validate?: (value: string) => ValidationError | true | null | undefined;
28
/** Validation behavior */
29
validationBehavior?: "aria" | "native";
30
/** Validation state */
31
validationState?: "valid" | "invalid";
32
/** Whether input is required */
33
isRequired?: boolean;
34
/** Whether input is read-only */
35
isReadOnly?: boolean;
36
/** Whether input is disabled */
37
isDisabled?: boolean;
38
/** Whether input is invalid */
39
isInvalid?: boolean;
40
/** Base container ref */
41
baseRef?: React.RefObject<HTMLDivElement>;
42
/** Whether to show helper content */
43
hasHelper?: boolean;
44
/** Input size variant */
45
size?: "sm" | "md" | "lg";
46
/** Border radius */
47
radius?: "none" | "sm" | "md" | "lg" | "full";
48
/** Visual variant */
49
variant?: "flat" | "bordered" | "underlined" | "faded";
50
/** Color theme */
51
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
52
/** Label placement */
53
labelPlacement?: "inside" | "outside" | "outside-left";
54
/** Whether input takes full width */
55
fullWidth?: boolean;
56
/** Whether to show clear button */
57
isClearable?: boolean;
58
/** Disable animations */
59
disableAnimation?: boolean;
60
/** Input type */
61
type?: "text" | "email" | "password" | "search" | "tel" | "url" | "number";
62
/** Start content (icon, etc.) */
63
startContent?: React.ReactNode;
64
/** End content (icon, button, etc.) */
65
endContent?: React.ReactNode;
66
/** Custom CSS class */
67
className?: string;
68
/** Slot-based styling */
69
classNames?: SlotsToClasses<InputSlots>;
70
/** Value change handler */
71
onValueChange?: (value: string) => void;
72
/** Clear button press handler */
73
onClear?: () => void;
74
}
75
76
type InputSlots =
77
| "base" | "mainWrapper" | "inputWrapper" | "innerWrapper"
78
| "input" | "clearButton" | "label" | "description"
79
| "errorMessage" | "helperWrapper";
80
81
function Input(props: InputProps): JSX.Element;
82
83
/**
84
* Hook for Input state management
85
*/
86
function useInput(props: InputProps): {
87
Component: React.ElementType;
88
label?: React.ReactNode;
89
description?: React.ReactNode;
90
errorMessage?: React.ReactNode;
91
isInvalid: boolean;
92
validationErrors: string[];
93
validationDetails: ValidationDetails;
94
slots: Record<InputSlots, string>;
95
classNames: SlotsToClasses<InputSlots>;
96
getBaseProps: () => any;
97
getLabelProps: () => any;
98
getInputProps: () => any;
99
getInputWrapperProps: () => any;
100
getInnerWrapperProps: () => any;
101
getMainWrapperProps: () => any;
102
getClearButtonProps: () => any;
103
getDescriptionProps: () => any;
104
getErrorMessageProps: () => any;
105
};
106
```
107
108
**Input Usage Examples:**
109
110
```typescript
111
import { Input } from "@nextui-org/react";
112
import { SearchIcon, EyeFilledIcon, EyeSlashFilledIcon } from "@heroicons/react/24/solid";
113
114
function InputExamples() {
115
const [isVisible, setIsVisible] = useState(false);
116
const [value, setValue] = useState("");
117
118
const toggleVisibility = () => setIsVisible(!isVisible);
119
120
const validateEmail = (value: string) => {
121
return value.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$/i);
122
};
123
124
const isInvalid = useMemo(() => {
125
if (value === "") return false;
126
return validateEmail(value) ? false : true;
127
}, [value]);
128
129
return (
130
<div className="space-y-4">
131
{/* Basic input */}
132
<Input
133
type="text"
134
label="Name"
135
placeholder="Enter your name"
136
labelPlacement="outside"
137
/>
138
139
{/* Email input with validation */}
140
<Input
141
value={value}
142
onValueChange={setValue}
143
isInvalid={isInvalid}
144
label="Email"
145
variant="bordered"
146
placeholder="Enter your email"
147
description="We'll never share your email with anyone else."
148
errorMessage={isInvalid && "Please enter a valid email"}
149
color={isInvalid ? "danger" : "success"}
150
className="max-w-xs"
151
/>
152
153
{/* Password input with toggle visibility */}
154
<Input
155
label="Password"
156
variant="bordered"
157
placeholder="Enter your password"
158
endContent={
159
<button className="focus:outline-none" type="button" onClick={toggleVisibility}>
160
{isVisible ? (
161
<EyeSlashFilledIcon className="text-2xl text-default-400 pointer-events-none" />
162
) : (
163
<EyeFilledIcon className="text-2xl text-default-400 pointer-events-none" />
164
)}
165
</button>
166
}
167
type={isVisible ? "text" : "password"}
168
className="max-w-xs"
169
/>
170
171
{/* Search input with icon */}
172
<Input
173
label="Search"
174
isClearable
175
radius="lg"
176
placeholder="Type to search..."
177
startContent={
178
<SearchIcon className="text-black/50 mb-0.5 dark:text-white/90 text-slate-400 pointer-events-none flex-shrink-0" />
179
}
180
/>
181
</div>
182
);
183
}
184
```
185
186
### Textarea
187
188
Multi-line text input component with automatic resizing and validation support.
189
190
```typescript { .api }
191
interface TextAreaProps {
192
/** Textarea content */
193
children?: React.ReactNode;
194
/** Textarea label */
195
label?: React.ReactNode;
196
/** Current textarea value */
197
value?: string;
198
/** Default value for uncontrolled mode */
199
defaultValue?: string;
200
/** Placeholder text */
201
placeholder?: string;
202
/** Helper description text */
203
description?: React.ReactNode;
204
/** Error message content */
205
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
206
/** Validation function */
207
validate?: (value: string) => ValidationError | true | null | undefined;
208
/** Validation behavior */
209
validationBehavior?: "aria" | "native";
210
/** Validation state */
211
validationState?: "valid" | "invalid";
212
/** Whether textarea is required */
213
isRequired?: boolean;
214
/** Whether textarea is read-only */
215
isReadOnly?: boolean;
216
/** Whether textarea is disabled */
217
isDisabled?: boolean;
218
/** Whether textarea is invalid */
219
isInvalid?: boolean;
220
/** Textarea size variant */
221
size?: "sm" | "md" | "lg";
222
/** Border radius */
223
radius?: "none" | "sm" | "md" | "lg" | "full";
224
/** Visual variant */
225
variant?: "flat" | "bordered" | "underlined" | "faded";
226
/** Color theme */
227
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
228
/** Label placement */
229
labelPlacement?: "inside" | "outside" | "outside-left";
230
/** Whether textarea takes full width */
231
fullWidth?: boolean;
232
/** Disable animations */
233
disableAnimation?: boolean;
234
/** Minimum number of rows */
235
minRows?: number;
236
/** Maximum number of rows */
237
maxRows?: number;
238
/** Whether to cache height for performance */
239
cacheMeasurements?: boolean;
240
/** Custom CSS class */
241
className?: string;
242
/** Slot-based styling */
243
classNames?: SlotsToClasses<InputSlots>;
244
/** Value change handler */
245
onValueChange?: (value: string) => void;
246
}
247
248
function Textarea(props: TextAreaProps): JSX.Element;
249
```
250
251
**Textarea Usage Example:**
252
253
```typescript
254
import { Textarea } from "@nextui-org/react";
255
256
function TextareaExample() {
257
return (
258
<div className="space-y-4">
259
<Textarea
260
label="Description"
261
placeholder="Enter your description"
262
description="Provide a detailed description of your project"
263
className="max-w-xs"
264
/>
265
266
<Textarea
267
isRequired
268
label="Feedback"
269
labelPlacement="outside"
270
placeholder="Share your feedback..."
271
variant="bordered"
272
minRows={3}
273
maxRows={8}
274
className="max-w-lg"
275
/>
276
</div>
277
);
278
}
279
```
280
281
### Select
282
283
Dropdown selection component with search, multiple selection, and custom item rendering support.
284
285
```typescript { .api }
286
interface SelectProps<T = object> {
287
/** Select content and options */
288
children?: React.ReactNode;
289
/** Data items for dynamic rendering */
290
items?: Iterable<T>;
291
/** Select label */
292
label?: React.ReactNode;
293
/** Placeholder text when no selection */
294
placeholder?: string;
295
/** Helper description text */
296
description?: React.ReactNode;
297
/** Error message content */
298
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
299
/** Validation function */
300
validate?: (value: SelectValue<T>) => ValidationError | true | null | undefined;
301
/** Selection mode */
302
selectionMode?: "single" | "multiple";
303
/** Currently selected keys */
304
selectedKeys?: "all" | Iterable<React.Key>;
305
/** Default selected keys for uncontrolled mode */
306
defaultSelectedKeys?: "all" | Iterable<React.Key>;
307
/** Prevent empty selection */
308
disallowEmptySelection?: boolean;
309
/** Whether popover should flip to fit */
310
shouldFlip?: boolean;
311
/** Whether select is required */
312
isRequired?: boolean;
313
/** Whether select is invalid */
314
isInvalid?: boolean;
315
/** Whether select is disabled */
316
isDisabled?: boolean;
317
/** Whether select is in loading state */
318
isLoading?: boolean;
319
/** Select size variant */
320
size?: "sm" | "md" | "lg";
321
/** Border radius */
322
radius?: "none" | "sm" | "md" | "lg" | "full";
323
/** Visual variant */
324
variant?: "flat" | "bordered" | "underlined" | "faded";
325
/** Color theme */
326
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
327
/** Label placement */
328
labelPlacement?: "inside" | "outside" | "outside-left";
329
/** Whether select takes full width */
330
fullWidth?: boolean;
331
/** Popover placement */
332
placement?: Placement;
333
/** Start content (icon, etc.) */
334
startContent?: React.ReactNode;
335
/** End content (icon, button, etc.) */
336
endContent?: React.ReactNode;
337
/** Selector icon (dropdown arrow) */
338
selectorIcon?: React.ReactNode;
339
/** Disable animations */
340
disableAnimation?: boolean;
341
/** Disable selector icon animation */
342
disableSelectorIconRotation?: boolean;
343
/** Custom scroll reference */
344
scrollRef?: React.RefObject<HTMLElement>;
345
/** Listbox props */
346
listboxProps?: Partial<ListboxProps>;
347
/** Popover props */
348
popoverProps?: Partial<PopoverProps>;
349
/** Spinner props for loading state */
350
spinnerProps?: Partial<SpinnerProps>;
351
/** Custom CSS class */
352
className?: string;
353
/** Slot-based styling */
354
classNames?: SlotsToClasses<SelectSlots>;
355
/** Selection change handler */
356
onSelectionChange?: (keys: Selection) => void;
357
/** Open state change handler */
358
onOpenChange?: (isOpen: boolean) => void;
359
/** Close handler */
360
onClose?: () => void;
361
}
362
363
type SelectSlots =
364
| "base" | "label" | "trigger" | "innerWrapper" | "selectorIcon"
365
| "value" | "listboxWrapper" | "listbox" | "popoverContent"
366
| "helperWrapper" | "description" | "errorMessage";
367
368
type SelectValue<T> = T | null | undefined;
369
370
function Select<T = object>(props: SelectProps<T>): JSX.Element;
371
372
/**
373
* Hook for Select state management
374
*/
375
function useSelect<T = object>(props: UseSelectProps<T>): {
376
Component: React.ElementType;
377
state: SelectState<T>;
378
slots: Record<SelectSlots, string>;
379
classNames: SlotsToClasses<SelectSlots>;
380
isOpen: boolean;
381
isLoading?: boolean;
382
getSelectProps: () => any;
383
getTriggerProps: () => any;
384
getValueProps: () => any;
385
getListboxProps: () => any;
386
getPopoverProps: () => any;
387
};
388
389
interface UseSelectProps<T> extends Omit<SelectProps<T>, 'children'> {
390
/** Trigger ref */
391
triggerRef?: React.RefObject<HTMLElement>;
392
/** Value ref */
393
valueRef?: React.RefObject<HTMLElement>;
394
/** Listbox ref */
395
listboxRef?: React.RefObject<HTMLElement>;
396
/** Popover ref */
397
popoverRef?: React.RefObject<HTMLDivElement>;
398
}
399
```
400
401
### Select Items
402
403
Components for defining select options and sections.
404
405
```typescript { .api }
406
// SelectItem is an alias for ListboxItem
407
interface SelectItemProps {
408
/** Item key identifier */
409
key?: React.Key;
410
/** Item text content */
411
children?: React.ReactNode;
412
/** Item text value for controlled components */
413
textValue?: string;
414
/** Whether item is disabled */
415
isDisabled?: boolean;
416
/** Whether to hide selected indicator */
417
hideSelectedIcon?: boolean;
418
/** Item start content (icon, avatar, etc.) */
419
startContent?: React.ReactNode;
420
/** Item end content (icon, badge, etc.) */
421
endContent?: React.ReactNode;
422
/** Item description text */
423
description?: React.ReactNode;
424
/** Custom CSS class */
425
className?: string;
426
/** Slot-based styling */
427
classNames?: SlotsToClasses<ListboxItemSlots>;
428
}
429
430
// SelectSection is an alias for ListboxSection
431
interface SelectSectionProps {
432
/** Section title */
433
title?: React.ReactNode;
434
/** Section items */
435
children?: React.ReactNode;
436
/** Whether to hide divider */
437
hideDivider?: boolean;
438
/** Whether to show divider */
439
showDivider?: boolean;
440
/** Divider props */
441
dividerProps?: DividerProps;
442
/** Item heading */
443
heading?: React.ReactNode;
444
/** Custom CSS class */
445
className?: string;
446
/** Slot-based styling */
447
classNames?: SlotsToClasses<ListboxSectionSlots>;
448
}
449
450
const SelectItem: React.FC<SelectItemProps>;
451
const SelectSection: React.FC<SelectSectionProps>;
452
```
453
454
**Select Usage Examples:**
455
456
```typescript
457
import { Select, SelectItem, SelectSection } from "@nextui-org/react";
458
459
function SelectExamples() {
460
const animals = [
461
{key: "cat", label: "Cat"},
462
{key: "dog", label: "Dog"},
463
{key: "elephant", label: "Elephant"},
464
{key: "lion", label: "Lion"},
465
{key: "tiger", label: "Tiger"},
466
];
467
468
const [selectedValue, setSelectedValue] = useState(new Set(["cat"]));
469
470
return (
471
<div className="space-y-4">
472
{/* Basic select */}
473
<Select
474
label="Favorite Animal"
475
placeholder="Select an animal"
476
className="max-w-xs"
477
>
478
{animals.map((animal) => (
479
<SelectItem key={animal.key}>
480
{animal.label}
481
</SelectItem>
482
))}
483
</Select>
484
485
{/* Multiple selection */}
486
<Select
487
label="Animals"
488
selectionMode="multiple"
489
placeholder="Select animals"
490
selectedKeys={selectedValue}
491
onSelectionChange={setSelectedValue}
492
className="max-w-xs"
493
>
494
{animals.map((animal) => (
495
<SelectItem key={animal.key}>
496
{animal.label}
497
</SelectItem>
498
))}
499
</Select>
500
501
{/* Select with sections */}
502
<Select
503
label="Pets by category"
504
placeholder="Select a pet"
505
className="max-w-xs"
506
>
507
<SelectSection title="Mammals">
508
<SelectItem key="cat">Cat</SelectItem>
509
<SelectItem key="dog">Dog</SelectItem>
510
</SelectSection>
511
<SelectSection title="Birds">
512
<SelectItem key="parrot">Parrot</SelectItem>
513
<SelectItem key="canary">Canary</SelectItem>
514
</SelectSection>
515
</Select>
516
517
{/* Dynamic items */}
518
<Select
519
items={animals}
520
label="Dynamic Animals"
521
placeholder="Select an animal"
522
className="max-w-xs"
523
>
524
{(item) => <SelectItem key={item.key}>{item.label}</SelectItem>}
525
</Select>
526
</div>
527
);
528
}
529
```
530
531
### Checkbox
532
533
Individual checkbox component with indeterminate state support and custom styling.
534
535
```typescript { .api }
536
interface CheckboxProps {
537
/** Checkbox label content */
538
children?: React.ReactNode;
539
/** Checkbox value */
540
value?: string;
541
/** Whether checkbox is selected */
542
isSelected?: boolean;
543
/** Default selection state */
544
defaultSelected?: boolean;
545
/** Whether checkbox is indeterminate */
546
isIndeterminate?: boolean;
547
/** Whether checkbox is required */
548
isRequired?: boolean;
549
/** Whether checkbox is read-only */
550
isReadOnly?: boolean;
551
/** Whether checkbox is disabled */
552
isDisabled?: boolean;
553
/** Whether checkbox is invalid */
554
isInvalid?: boolean;
555
/** Validation state */
556
validationState?: "valid" | "invalid";
557
/** Checkbox size */
558
size?: "sm" | "md" | "lg";
559
/** Color theme */
560
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
561
/** Border radius */
562
radius?: "none" | "sm" | "md" | "lg" | "full";
563
/** Line through text when selected */
564
lineThrough?: boolean;
565
/** Disable animations */
566
disableAnimation?: boolean;
567
/** Custom icon for checkbox */
568
icon?: React.ReactNode | ((props: CheckboxIconProps) => React.ReactNode);
569
/** Custom CSS class */
570
className?: string;
571
/** Slot-based styling */
572
classNames?: SlotsToClasses<CheckboxSlots>;
573
/** Selection change handler */
574
onValueChange?: (isSelected: boolean) => void;
575
}
576
577
type CheckboxSlots = "base" | "wrapper" | "icon" | "label";
578
579
function Checkbox(props: CheckboxProps): JSX.Element;
580
581
/**
582
* Hook for Checkbox state management
583
*/
584
function useCheckbox(props: CheckboxProps): {
585
Component: React.ElementType;
586
slots: Record<CheckboxSlots, string>;
587
classNames: SlotsToClasses<CheckboxSlots>;
588
isSelected: boolean;
589
isPressed: boolean;
590
isFocused: boolean;
591
isInvalid: boolean;
592
getBaseProps: () => any;
593
getWrapperProps: () => any;
594
getInputProps: () => any;
595
getLabelProps: () => any;
596
getIconProps: () => any;
597
};
598
```
599
600
### Checkbox Icon
601
602
Customizable icon component for checkbox states.
603
604
```typescript { .api }
605
interface CheckboxIconProps {
606
/** Icon data attributes */
607
"data-checked"?: string;
608
/** Whether checkbox is selected */
609
isSelected?: boolean;
610
/** Whether checkbox is indeterminate */
611
isIndeterminate?: boolean;
612
/** Disable animations */
613
disableAnimation?: boolean;
614
/** Custom CSS class */
615
className?: string;
616
}
617
618
function CheckboxIcon(props: CheckboxIconProps): JSX.Element;
619
```
620
621
### Checkbox Group
622
623
Container for managing groups of related checkboxes with shared state and validation.
624
625
```typescript { .api }
626
interface CheckboxGroupProps {
627
/** Group label */
628
label?: React.ReactNode;
629
/** Checkbox items */
630
children?: React.ReactNode;
631
/** Currently selected values */
632
value?: string[];
633
/** Default selected values */
634
defaultValue?: string[];
635
/** Group name attribute */
636
name?: string;
637
/** Group size */
638
size?: "sm" | "md" | "lg";
639
/** Color theme */
640
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
641
/** Border radius for all checkboxes */
642
radius?: "none" | "sm" | "md" | "lg" | "full";
643
/** Group orientation */
644
orientation?: "horizontal" | "vertical";
645
/** Whether group is required */
646
isRequired?: boolean;
647
/** Whether group is read-only */
648
isReadOnly?: boolean;
649
/** Whether group is disabled */
650
isDisabled?: boolean;
651
/** Whether group is invalid */
652
isInvalid?: boolean;
653
/** Validation state */
654
validationState?: "valid" | "invalid";
655
/** Helper description text */
656
description?: React.ReactNode;
657
/** Error message content */
658
errorMessage?: React.ReactNode;
659
/** Disable animations */
660
disableAnimation?: boolean;
661
/** Custom CSS class */
662
className?: string;
663
/** Slot-based styling */
664
classNames?: SlotsToClasses<CheckboxGroupSlots>;
665
/** Value change handler */
666
onValueChange?: (value: string[]) => void;
667
}
668
669
type CheckboxGroupSlots = "base" | "label" | "wrapper" | "description" | "errorMessage";
670
671
function CheckboxGroup(props: CheckboxGroupProps): JSX.Element;
672
673
/**
674
* Hook for CheckboxGroup state management
675
*/
676
function useCheckboxGroup(props: CheckboxGroupProps): {
677
Component: React.ElementType;
678
slots: Record<CheckboxGroupSlots, string>;
679
classNames: SlotsToClasses<CheckboxGroupSlots>;
680
groupState: CheckboxGroupState;
681
getGroupProps: () => any;
682
getLabelProps: () => any;
683
getWrapperProps: () => any;
684
getDescriptionProps: () => any;
685
getErrorMessageProps: () => any;
686
};
687
```
688
689
**Checkbox Usage Examples:**
690
691
```typescript
692
import { Checkbox, CheckboxGroup } from "@nextui-org/react";
693
694
function CheckboxExamples() {
695
const [selected, setSelected] = useState(["argentina"]);
696
697
return (
698
<div className="space-y-6">
699
{/* Individual checkboxes */}
700
<div className="space-y-2">
701
<Checkbox defaultSelected>Option 1</Checkbox>
702
<Checkbox isIndeterminate>Option 2</Checkbox>
703
<Checkbox isDisabled>Option 3</Checkbox>
704
</div>
705
706
{/* Checkbox group */}
707
<CheckboxGroup
708
label="Select countries"
709
color="secondary"
710
value={selected}
711
onValueChange={setSelected}
712
description="Choose your favorite countries"
713
>
714
<Checkbox value="argentina">Argentina</Checkbox>
715
<Checkbox value="venezuela">Venezuela</Checkbox>
716
<Checkbox value="brazil">Brazil</Checkbox>
717
<Checkbox value="colombia">Colombia</Checkbox>
718
</CheckboxGroup>
719
720
{/* Custom icon checkbox */}
721
<Checkbox
722
icon={<HeartIcon />}
723
color="danger"
724
defaultSelected
725
>
726
Add to favorites
727
</Checkbox>
728
</div>
729
);
730
}
731
```
732
733
### Checkbox Group Context
734
735
Context system for sharing checkbox group state.
736
737
```typescript { .api }
738
interface CheckboxGroupProviderProps {
739
children: React.ReactNode;
740
value: CheckboxGroupContextValue;
741
}
742
743
interface CheckboxGroupContextValue {
744
groupState: CheckboxGroupState;
745
size?: "sm" | "md" | "lg";
746
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
747
radius?: "none" | "sm" | "md" | "lg" | "full";
748
isInvalid?: boolean;
749
isReadOnly?: boolean;
750
isDisabled?: boolean;
751
disableAnimation?: boolean;
752
}
753
754
const CheckboxGroupProvider: React.FC<CheckboxGroupProviderProps>;
755
756
/**
757
* Hook to access checkbox group context
758
* @throws Error if used outside CheckboxGroupProvider
759
*/
760
function useCheckboxGroupContext(): CheckboxGroupContextValue | undefined;
761
```
762
763
### Radio
764
765
Individual radio button component for single selection within groups.
766
767
```typescript { .api }
768
interface RadioProps {
769
/** Radio label content */
770
children?: React.ReactNode;
771
/** Radio value */
772
value: string;
773
/** Radio size */
774
size?: "sm" | "md" | "lg";
775
/** Color theme */
776
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
777
/** Whether radio is disabled */
778
isDisabled?: boolean;
779
/** Whether radio is invalid */
780
isInvalid?: boolean;
781
/** Custom description */
782
description?: React.ReactNode;
783
/** Disable animations */
784
disableAnimation?: boolean;
785
/** Custom CSS class */
786
className?: string;
787
/** Slot-based styling */
788
classNames?: SlotsToClasses<RadioSlots>;
789
}
790
791
type RadioSlots = "base" | "wrapper" | "labelWrapper" | "control" | "label" | "description";
792
793
function Radio(props: RadioProps): JSX.Element;
794
795
/**
796
* Hook for Radio state management
797
*/
798
function useRadio(props: RadioProps): {
799
Component: React.ElementType;
800
slots: Record<RadioSlots, string>;
801
classNames: SlotsToClasses<RadioSlots>;
802
isSelected: boolean;
803
isPressed: boolean;
804
isFocused: boolean;
805
isInvalid: boolean;
806
getBaseProps: () => any;
807
getWrapperProps: () => any;
808
getInputProps: () => any;
809
getLabelWrapperProps: () => any;
810
getLabelProps: () => any;
811
getControlProps: () => any;
812
getDescriptionProps: () => any;
813
};
814
```
815
816
### Radio Group
817
818
Container for managing groups of radio buttons with single selection state.
819
820
```typescript { .api }
821
interface RadioGroupProps {
822
/** Group label */
823
label?: React.ReactNode;
824
/** Radio items */
825
children?: React.ReactNode;
826
/** Currently selected value */
827
value?: string;
828
/** Default selected value */
829
defaultValue?: string;
830
/** Group name attribute */
831
name?: string;
832
/** Group size */
833
size?: "sm" | "md" | "lg";
834
/** Color theme */
835
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
836
/** Group orientation */
837
orientation?: "horizontal" | "vertical";
838
/** Whether group is required */
839
isRequired?: boolean;
840
/** Whether group is read-only */
841
isReadOnly?: boolean;
842
/** Whether group is disabled */
843
isDisabled?: boolean;
844
/** Whether group is invalid */
845
isInvalid?: boolean;
846
/** Validation state */
847
validationState?: "valid" | "invalid";
848
/** Helper description text */
849
description?: React.ReactNode;
850
/** Error message content */
851
errorMessage?: React.ReactNode;
852
/** Disable animations */
853
disableAnimation?: boolean;
854
/** Custom CSS class */
855
className?: string;
856
/** Slot-based styling */
857
classNames?: SlotsToClasses<RadioGroupSlots>;
858
/** Value change handler */
859
onValueChange?: (value: string) => void;
860
}
861
862
type RadioGroupSlots = "base" | "label" | "wrapper" | "description" | "errorMessage";
863
864
function RadioGroup(props: RadioGroupProps): JSX.Element;
865
866
/**
867
* Hook for RadioGroup state management
868
*/
869
function useRadioGroup(props: RadioGroupProps): {
870
Component: React.ElementType;
871
slots: Record<RadioGroupSlots, string>;
872
classNames: SlotsToClasses<RadioGroupSlots>;
873
groupState: RadioGroupState;
874
getGroupProps: () => any;
875
getLabelProps: () => any;
876
getWrapperProps: () => any;
877
getDescriptionProps: () => any;
878
getErrorMessageProps: () => any;
879
};
880
```
881
882
**Radio Usage Example:**
883
884
```typescript
885
import { RadioGroup, Radio } from "@nextui-org/react";
886
887
function RadioExample() {
888
const [selected, setSelected] = useState("london");
889
890
return (
891
<RadioGroup
892
label="Select your favorite city"
893
value={selected}
894
onValueChange={setSelected}
895
orientation="horizontal"
896
>
897
<Radio value="buenos-aires">Buenos Aires</Radio>
898
<Radio value="sydney">Sydney</Radio>
899
<Radio value="san-francisco">San Francisco</Radio>
900
<Radio value="london">London</Radio>
901
<Radio value="tokyo">Tokyo</Radio>
902
</RadioGroup>
903
);
904
}
905
```
906
907
### Switch
908
909
Toggle switch component for boolean states with customizable appearance and behavior.
910
911
```typescript { .api }
912
interface SwitchProps {
913
/** Switch label content */
914
children?: React.ReactNode;
915
/** Whether switch is selected */
916
isSelected?: boolean;
917
/** Default selection state */
918
defaultSelected?: boolean;
919
/** Switch value */
920
value?: string;
921
/** Switch name attribute */
922
name?: string;
923
/** Switch size */
924
size?: "sm" | "md" | "lg";
925
/** Color theme */
926
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
927
/** Custom start content */
928
startContent?: React.ReactNode;
929
/** Custom end content */
930
endContent?: React.ReactNode;
931
/** Custom thumb icon */
932
thumbIcon?: React.ReactNode | ((props: SwitchThumbIconProps) => React.ReactNode);
933
/** Whether switch is required */
934
isRequired?: boolean;
935
/** Whether switch is read-only */
936
isReadOnly?: boolean;
937
/** Whether switch is disabled */
938
isDisabled?: boolean;
939
/** Disable animations */
940
disableAnimation?: boolean;
941
/** Custom CSS class */
942
className?: string;
943
/** Slot-based styling */
944
classNames?: SlotsToClasses<SwitchSlots>;
945
/** Selection change handler */
946
onValueChange?: (isSelected: boolean) => void;
947
}
948
949
type SwitchSlots =
950
| "base" | "wrapper" | "thumb" | "startContent"
951
| "endContent" | "thumbIcon" | "label";
952
953
interface SwitchThumbIconProps {
954
/** Icon data attributes */
955
"data-selected"?: string;
956
/** Whether switch is selected */
957
isSelected?: boolean;
958
/** Custom CSS class */
959
className?: string;
960
}
961
962
function Switch(props: SwitchProps): JSX.Element;
963
964
/**
965
* Hook for Switch state management
966
*/
967
function useSwitch(props: SwitchProps): {
968
Component: React.ElementType;
969
slots: Record<SwitchSlots, string>;
970
classNames: SlotsToClasses<SwitchSlots>;
971
isSelected: boolean;
972
isPressed: boolean;
973
isFocused: boolean;
974
getBaseProps: () => any;
975
getWrapperProps: () => any;
976
getInputProps: () => any;
977
getLabelProps: () => any;
978
getThumbProps: () => any;
979
getStartContentProps: () => any;
980
getEndContentProps: () => any;
981
getThumbIconProps: () => any;
982
};
983
```
984
985
**Switch Usage Examples:**
986
987
```typescript
988
import { Switch } from "@nextui-org/react";
989
import { MoonIcon, SunIcon } from "@heroicons/react/24/solid";
990
991
function SwitchExamples() {
992
return (
993
<div className="space-y-4">
994
{/* Basic switch */}
995
<Switch defaultSelected>Airplane mode</Switch>
996
997
{/* Switch with icons */}
998
<Switch
999
defaultSelected
1000
size="lg"
1001
color="success"
1002
startContent={<SunIcon />}
1003
endContent={<MoonIcon />}
1004
>
1005
Dark mode
1006
</Switch>
1007
1008
{/* Switch with custom thumb icon */}
1009
<Switch
1010
defaultSelected
1011
size="lg"
1012
color="secondary"
1013
thumbIcon={({ isSelected, className }) =>
1014
isSelected ? (
1015
<SunIcon className={className} />
1016
) : (
1017
<MoonIcon className={className} />
1018
)
1019
}
1020
>
1021
Theme toggle
1022
</Switch>
1023
</div>
1024
);
1025
}
1026
```
1027
1028
### Slider
1029
1030
Range slider component for selecting numeric values within a defined range.
1031
1032
```typescript { .api }
1033
interface SliderProps {
1034
/** Slider label */
1035
label?: React.ReactNode;
1036
/** Current slider value(s) */
1037
value?: SliderValue;
1038
/** Default value for uncontrolled mode */
1039
defaultValue?: SliderValue;
1040
/** Minimum value */
1041
minValue?: number;
1042
/** Maximum value */
1043
maxValue?: number;
1044
/** Step increment */
1045
step?: number;
1046
/** Format options for value display */
1047
formatOptions?: Intl.NumberFormatOptions;
1048
/** Slider size */
1049
size?: "sm" | "md" | "lg";
1050
/** Color theme */
1051
color?: "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
1052
/** Fill offset for range sliders */
1053
fillOffset?: number;
1054
/** Step marks configuration */
1055
marks?: SliderStepMark[];
1056
/** Whether to hide thumb labels */
1057
hideThumb?: boolean;
1058
/** Whether to hide value label */
1059
hideValue?: boolean;
1060
/** Show steps as marks */
1061
showSteps?: boolean;
1062
/** Show tooltip on hover/focus */
1063
showTooltip?: boolean;
1064
/** Show outline on focus */
1065
showOutline?: boolean;
1066
/** Disable thumb scale animation */
1067
disableThumbScale?: boolean;
1068
/** Whether slider is required */
1069
isRequired?: boolean;
1070
/** Whether slider is disabled */
1071
isDisabled?: boolean;
1072
/** Slider orientation */
1073
orientation?: "horizontal" | "vertical";
1074
/** Tooltip properties */
1075
tooltipProps?: Partial<TooltipProps>;
1076
/** Custom thumb renderer */
1077
renderThumb?: (props: SliderRenderThumbProps) => React.ReactNode;
1078
/** Custom label renderer */
1079
renderLabel?: (props: SliderRenderLabelProps) => React.ReactNode;
1080
/** Custom value renderer */
1081
renderValue?: (props: SliderRenderValueProps) => React.ReactNode;
1082
/** Custom CSS class */
1083
className?: string;
1084
/** Slot-based styling */
1085
classNames?: SlotsToClasses<SliderSlots>;
1086
/** Value change handler */
1087
onChange?: (value: SliderValue) => void;
1088
/** Value change end handler */
1089
onChangeEnd?: (value: SliderValue) => void;
1090
}
1091
1092
type SliderValue = number | number[];
1093
1094
interface SliderStepMark {
1095
/** Step value */
1096
value: number;
1097
/** Step label */
1098
label?: React.ReactNode;
1099
}
1100
1101
interface SliderRenderThumbProps {
1102
/** Thumb index for multi-thumb sliders */
1103
index?: number;
1104
/** Current value */
1105
value?: number;
1106
/** Value as percentage */
1107
valueLabel?: string;
1108
/** Whether thumb has focus */
1109
isFocused?: boolean;
1110
/** Whether thumb is being dragged */
1111
isDragging?: boolean;
1112
/** Whether slider is disabled */
1113
isDisabled?: boolean;
1114
/** Thumb props */
1115
getThumbProps: (props?: any) => any;
1116
}
1117
1118
interface SliderRenderLabelProps {
1119
/** Current value(s) */
1120
value?: SliderValue;
1121
/** Formatted value text */
1122
valueLabel?: string;
1123
/** Whether slider has focus */
1124
isFocused?: boolean;
1125
/** Whether slider is disabled */
1126
isDisabled?: boolean;
1127
}
1128
1129
interface SliderRenderValueProps extends SliderRenderLabelProps {}
1130
1131
type SliderSlots =
1132
| "base" | "labelWrapper" | "label" | "value" | "trackWrapper"
1133
| "track" | "filler" | "thumb" | "mark" | "step";
1134
1135
function Slider(props: SliderProps): JSX.Element;
1136
1137
/**
1138
* Hook for Slider state management
1139
*/
1140
function useSlider(props: SliderProps): {
1141
Component: React.ElementType;
1142
slots: Record<SliderSlots, string>;
1143
classNames: SlotsToClasses<SliderSlots>;
1144
state: SliderState;
1145
getBaseProps: () => any;
1146
getLabelWrapperProps: () => any;
1147
getLabelProps: () => any;
1148
getValueProps: () => any;
1149
getTrackWrapperProps: () => any;
1150
getTrackProps: () => any;
1151
getFillerProps: () => any;
1152
getThumbProps: (index?: number) => any;
1153
getMarkProps: (mark: SliderStepMark, index: number) => any;
1154
getStepProps: (step: number, index: number) => any;
1155
};
1156
```
1157
1158
**Slider Usage Examples:**
1159
1160
```typescript
1161
import { Slider } from "@nextui-org/react";
1162
1163
function SliderExamples() {
1164
const [value, setValue] = useState(40);
1165
const [rangeValue, setRangeValue] = useState([100, 500]);
1166
1167
return (
1168
<div className="space-y-8">
1169
{/* Basic slider */}
1170
<Slider
1171
label="Temperature"
1172
step={1}
1173
minValue={0}
1174
maxValue={100}
1175
value={value}
1176
onChange={setValue}
1177
className="max-w-md"
1178
formatOptions={{style: "unit", unit: "celsius"}}
1179
/>
1180
1181
{/* Range slider */}
1182
<Slider
1183
label="Price Range"
1184
step={50}
1185
minValue={0}
1186
maxValue={1000}
1187
value={rangeValue}
1188
onChange={setRangeValue}
1189
className="max-w-md"
1190
formatOptions={{style: "currency", currency: "USD"}}
1191
/>
1192
1193
{/* Slider with steps */}
1194
<Slider
1195
label="Volume"
1196
step={10}
1197
minValue={0}
1198
maxValue={100}
1199
defaultValue={30}
1200
showSteps
1201
showTooltip
1202
showOutline
1203
className="max-w-md"
1204
marks={[
1205
{value: 20, label: "20%"},
1206
{value: 50, label: "50%"},
1207
{value: 80, label: "80%"},
1208
]}
1209
/>
1210
</div>
1211
);
1212
}
1213
```
1214
1215
### Textarea
1216
1217
A multi-line text input component with auto-resize capabilities and enhanced styling options.
1218
1219
```typescript { .api }
1220
interface TextAreaProps {
1221
/** Input label */
1222
label?: React.ReactNode;
1223
/** Current textarea value */
1224
value?: string;
1225
/** Default textarea value */
1226
defaultValue?: string;
1227
/** Input placeholder text */
1228
placeholder?: string;
1229
/** Helper description text */
1230
description?: React.ReactNode;
1231
/** Error message */
1232
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
1233
/** Validation function */
1234
validate?: (value: string) => ValidationError | true | null | undefined;
1235
/** Validation behavior */
1236
validationBehavior?: "aria" | "native";
1237
/** Whether textarea is required */
1238
isRequired?: boolean;
1239
/** Whether textarea is read-only */
1240
isReadOnly?: boolean;
1241
/** Whether textarea is disabled */
1242
isDisabled?: boolean;
1243
/** Whether textarea is invalid */
1244
isInvalid?: boolean;
1245
/** Auto focus on mount */
1246
autoFocus?: boolean;
1247
/** Textarea size */
1248
size?: "sm" | "md" | "lg";
1249
/** Border radius */
1250
radius?: "none" | "sm" | "md" | "lg" | "full";
1251
/** Visual variant */
1252
variant?: "flat" | "bordered" | "underlined" | "faded";
1253
/** Color theme */
1254
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
1255
/** Label placement */
1256
labelPlacement?: "inside" | "outside" | "outside-left";
1257
/** Whether textarea takes full width */
1258
fullWidth?: boolean;
1259
/** Minimum number of visible text lines */
1260
minRows?: number;
1261
/** Maximum number of visible text lines */
1262
maxRows?: number;
1263
/** Show clear button */
1264
isClearable?: boolean;
1265
/** Disable animations */
1266
disableAnimation?: boolean;
1267
/** Disable auto resize */
1268
disableAutosize?: boolean;
1269
/** Cached row height for performance */
1270
cacheMeasurements?: boolean;
1271
/** Custom CSS class */
1272
className?: string;
1273
/** Slot-based styling */
1274
classNames?: SlotsToClasses<InputSlots>;
1275
/** Value change handler */
1276
onValueChange?: (value: string) => void;
1277
/** Clear handler */
1278
onClear?: () => void;
1279
}
1280
1281
function Textarea(props: TextAreaProps): JSX.Element;
1282
```
1283
1284
**Textarea Usage Examples:**
1285
1286
```typescript
1287
import { Textarea, Button, Card, CardBody } from "@nextui-org/react";
1288
1289
function TextareaExamples() {
1290
const [value, setValue] = useState("");
1291
const [message, setMessage] = useState("");
1292
1293
return (
1294
<Card className="max-w-lg">
1295
<CardBody className="space-y-4">
1296
{/* Basic textarea */}
1297
<Textarea
1298
label="Description"
1299
placeholder="Enter your description"
1300
value={value}
1301
onValueChange={setValue}
1302
/>
1303
1304
{/* Textarea with validation */}
1305
<Textarea
1306
isRequired
1307
label="Message"
1308
placeholder="Write your message here..."
1309
description="Minimum 10 characters required"
1310
value={message}
1311
onValueChange={setMessage}
1312
minRows={3}
1313
maxRows={8}
1314
validate={(value) => {
1315
if (value.length < 10) {
1316
return "Message must be at least 10 characters long";
1317
}
1318
return true;
1319
}}
1320
errorMessage={(validation) =>
1321
validation.isInvalid ? validation.validationErrors[0] : undefined
1322
}
1323
/>
1324
1325
{/* Disabled auto-resize textarea */}
1326
<Textarea
1327
label="Fixed Size"
1328
placeholder="This textarea doesn't auto-resize"
1329
disableAutosize
1330
minRows={4}
1331
variant="bordered"
1332
color="secondary"
1333
/>
1334
1335
{/* Textarea with clear functionality */}
1336
<Textarea
1337
label="Clearable Content"
1338
placeholder="Type something and clear it"
1339
isClearable
1340
variant="underlined"
1341
/>
1342
1343
<Button
1344
color="primary"
1345
isDisabled={message.length < 10}
1346
className="w-full"
1347
>
1348
Submit Message
1349
</Button>
1350
</CardBody>
1351
</Card>
1352
);
1353
}
1354
```
1355
1356
### Input OTP
1357
1358
A specialized input component for One-Time Password entry with individual character segments.
1359
1360
```typescript { .api }
1361
interface InputOTPProps {
1362
/** Number of OTP digits */
1363
length?: number;
1364
/** Current OTP value */
1365
value?: string;
1366
/** Default OTP value */
1367
defaultValue?: string;
1368
/** Input placeholder for each digit */
1369
placeholder?: string;
1370
/** Whether input is required */
1371
isRequired?: boolean;
1372
/** Whether input is disabled */
1373
isDisabled?: boolean;
1374
/** Whether input is invalid */
1375
isInvalid?: boolean;
1376
/** Input size */
1377
size?: "sm" | "md" | "lg";
1378
/** Border radius */
1379
radius?: "none" | "sm" | "md" | "lg" | "full";
1380
/** Visual variant */
1381
variant?: "flat" | "bordered" | "underlined" | "faded";
1382
/** Color theme */
1383
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
1384
/** Whether to allow only numeric input */
1385
allowedKeys?: RegExp;
1386
/** Custom CSS class */
1387
className?: string;
1388
/** Slot-based styling */
1389
classNames?: SlotsToClasses<InputOTPSlots>;
1390
/** Value change handler */
1391
onValueChange?: (value: string) => void;
1392
/** Complete handler (when all digits filled) */
1393
onComplete?: (value: string) => void;
1394
}
1395
1396
type InputOTPSlots = "base" | "segmentWrapper" | "segment" | "helperWrapper";
1397
1398
function InputOTP(props: InputOTPProps): JSX.Element;
1399
1400
/**
1401
* Hook for InputOTP state management
1402
*/
1403
function useInputOTP(props: InputOTPProps): {
1404
Component: React.ElementType;
1405
slots: Record<InputOTPSlots, string>;
1406
classNames: SlotsToClasses<InputOTPSlots>;
1407
getInputOTPProps: () => any;
1408
getSegmentProps: (index: number) => any;
1409
};
1410
```
1411
1412
**Input OTP Usage Examples:**
1413
1414
```typescript
1415
import { InputOTP, Card, CardHeader, CardBody, Button } from "@nextui-org/react";
1416
1417
function InputOTPExamples() {
1418
const [otp, setOtp] = useState("");
1419
const [verificationOTP, setVerificationOTP] = useState("");
1420
1421
const handleComplete = (value: string) => {
1422
console.log("OTP completed:", value);
1423
// Handle OTP verification
1424
};
1425
1426
return (
1427
<div className="space-y-6 max-w-sm mx-auto">
1428
<Card>
1429
<CardHeader>
1430
<h3>Email Verification</h3>
1431
</CardHeader>
1432
<CardBody className="space-y-4">
1433
<p className="text-sm text-default-500">
1434
Enter the 6-digit code sent to your email
1435
</p>
1436
1437
<InputOTP
1438
length={6}
1439
value={otp}
1440
onValueChange={setOtp}
1441
onComplete={handleComplete}
1442
placeholder="0"
1443
/>
1444
1445
<Button
1446
color="primary"
1447
isDisabled={otp.length !== 6}
1448
className="w-full"
1449
>
1450
Verify Code
1451
</Button>
1452
</CardBody>
1453
</Card>
1454
1455
<Card>
1456
<CardHeader>
1457
<h3>Custom Styled OTP</h3>
1458
</CardHeader>
1459
<CardBody className="space-y-4">
1460
<InputOTP
1461
length={4}
1462
value={verificationOTP}
1463
onValueChange={setVerificationOTP}
1464
variant="bordered"
1465
color="secondary"
1466
size="lg"
1467
radius="sm"
1468
allowedKeys={/^[0-9]$/}
1469
/>
1470
1471
<p className="text-xs text-default-400">
1472
Only numeric digits allowed
1473
</p>
1474
</CardBody>
1475
</Card>
1476
</div>
1477
);
1478
}
1479
```
1480
1481
## Input Component Types
1482
1483
```typescript { .api }
1484
// Common input types
1485
type InputSize = "sm" | "md" | "lg";
1486
type InputVariant = "flat" | "bordered" | "underlined" | "faded";
1487
type InputColor = "default" | "primary" | "secondary" | "success" | "warning" | "danger";
1488
type LabelPlacement = "inside" | "outside" | "outside-left";
1489
type ValidationBehavior = "aria" | "native";
1490
1491
// Validation types
1492
type ValidationError = string | string[];
1493
1494
interface ValidationResult {
1495
isInvalid: boolean;
1496
validationErrors: string[];
1497
validationDetails: ValidationDetails;
1498
}
1499
1500
interface ValidationDetails {
1501
[key: string]: any;
1502
}
1503
1504
// Selection types
1505
type Selection = "all" | Set<React.Key>;
1506
1507
// Group state interfaces
1508
interface CheckboxGroupState {
1509
readonly selectedKeys: Set<string>;
1510
readonly isDisabled: boolean;
1511
readonly isReadOnly: boolean;
1512
readonly isRequired: boolean;
1513
readonly isInvalid: boolean;
1514
readonly value: string[];
1515
addValue(value: string): void;
1516
removeValue(value: string): void;
1517
toggleValue(value: string): void;
1518
clearValue(): void;
1519
}
1520
1521
interface RadioGroupState {
1522
readonly selectedValue: string | null;
1523
readonly isDisabled: boolean;
1524
readonly isReadOnly: boolean;
1525
readonly isRequired: boolean;
1526
readonly isInvalid: boolean;
1527
setSelectedValue(value: string): void;
1528
}
1529
1530
interface SliderState {
1531
readonly values: number[];
1532
readonly focusedThumb: number | undefined;
1533
readonly isDisabled: boolean;
1534
getThumbValue(index: number): number;
1535
setThumbValue(index: number, value: number): void;
1536
incrementThumb(index: number, stepSize?: number): void;
1537
decrementThumb(index: number, stepSize?: number): void;
1538
}
1539
```