0
# Input Components
1
2
Form controls and interactive elements.
3
4
**⚠️ All inputs share [common input props](./common-props.md#common-input-props)**: `error`, `errorMessage`, `disabled`, `placeholder`, `icon`.
5
6
## Input Selection
7
8
| Component | Use Case | Key Props |
9
|-----------|----------|-----------|
10
| Button | Actions, submissions | `variant`, `loading`, `icon`, `iconPosition` |
11
| TextInput | Single-line text | Standard input props + `type` |
12
| NumberInput | Numeric values | `enableStepper`, `step`, `min`, `max`, `onSubmit` |
13
| Textarea | Multi-line text | `autoHeight`, `rows` |
14
| Switch | Boolean toggle | `checked`, `onChange`, `color` |
15
| Select | Single selection dropdown | `enableClear` + requires `<SelectItem>` children |
16
| MultiSelect | Multiple selections | `placeholderSearch` + requires `<MultiSelectItem>` |
17
| SearchSelect | Searchable single select | `searchValue`, `onSearchValueChange` + `<SearchSelectItem>` |
18
| DatePicker | Date selection | `minDate`, `maxDate`, `locale`, `weekStartsOn` |
19
| DateRangePicker | Date range | `enableSelect` + optional `<DateRangePickerItem>` presets |
20
| Tabs | Content switching | Use TabGroup/TabList/Tab/TabPanels/TabPanel |
21
22
## Controlled vs Uncontrolled
23
24
All inputs support both modes (controlled recommended):
25
26
```typescript
27
// Controlled (recommended)
28
const [value, setValue] = useState('');
29
<TextInput value={value} onValueChange={setValue} />
30
31
// Uncontrolled
32
<TextInput defaultValue="initial" />
33
```
34
35
## Button
36
37
```typescript { .api }
38
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
39
icon?: React.ElementType;
40
iconPosition?: "left" | "right";
41
size?: Size;
42
color?: Color;
43
variant?: "primary" | "secondary" | "light";
44
disabled?: boolean;
45
loading?: boolean;
46
loadingText?: string;
47
tooltip?: string;
48
}
49
```
50
51
**Examples:**
52
53
```typescript
54
import { Button } from '@tremor/react';
55
import { PlusIcon, DownloadIcon } from '@heroicons/react/24/outline';
56
57
<Button>Click me</Button>
58
<Button icon={PlusIcon} variant="primary" color="blue">Add Item</Button>
59
<Button loading loadingText="Saving...">Save</Button>
60
<Button icon={DownloadIcon} iconPosition="right" variant="secondary">Export</Button>
61
```
62
63
## TextInput
64
65
```typescript { .api }
66
interface TextInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
67
defaultValue?: string;
68
value?: string;
69
onValueChange?: (value: string) => void;
70
icon?: React.ElementType | React.JSXElementConstructor<any>;
71
error?: boolean;
72
errorMessage?: string;
73
disabled?: boolean;
74
// Plus all standard HTML input props: type, placeholder, pattern, etc.
75
}
76
```
77
78
**Examples:**
79
80
```typescript
81
import { TextInput } from '@tremor/react';
82
import { MagnifyingGlassIcon, EnvelopeIcon } from '@heroicons/react/24/outline';
83
84
// With icon
85
<TextInput icon={MagnifyingGlassIcon} placeholder="Search..." />
86
87
// With validation
88
function EmailInput() {
89
const [email, setEmail] = useState('');
90
const [error, setError] = useState('');
91
92
return (
93
<TextInput
94
icon={EnvelopeIcon}
95
type="email"
96
value={email}
97
onValueChange={(v) => {
98
setEmail(v);
99
setError(v && !v.includes('@') ? 'Invalid email' : '');
100
}}
101
error={!!error}
102
errorMessage={error}
103
/>
104
);
105
}
106
```
107
108
## NumberInput
109
110
```typescript { .api }
111
interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'> {
112
value?: number;
113
defaultValue?: number;
114
onValueChange?: (value: number) => void;
115
step?: string | number;
116
enableStepper?: boolean; // Show +/- buttons
117
onSubmit?: (value: number) => void;
118
min?: number;
119
max?: number;
120
icon?: React.ElementType;
121
error?: boolean;
122
errorMessage?: string;
123
disabled?: boolean;
124
}
125
```
126
127
**Examples:**
128
129
```typescript
130
import { NumberInput } from '@tremor/react';
131
132
<NumberInput placeholder="Enter amount" min={0} max={1000} />
133
<NumberInput defaultValue={10} step={5} enableStepper={true} />
134
135
// Controlled with decimals
136
const [price, setPrice] = useState(19.99);
137
<NumberInput value={price} onValueChange={setPrice} step={0.01} enableStepper={true} />
138
```
139
140
## Textarea
141
142
```typescript { .api }
143
interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
144
defaultValue?: string | number;
145
value?: string | number;
146
error?: boolean;
147
errorMessage?: string;
148
disabled?: boolean;
149
autoHeight?: boolean; // Automatically adjust height to content
150
onValueChange?: (value: any) => void;
151
}
152
```
153
154
**Examples:**
155
156
```typescript
157
import { Textarea } from '@tremor/react';
158
159
<Textarea placeholder="Enter your message..." rows={4} />
160
<Textarea autoHeight={true} placeholder="Auto-expanding textarea" />
161
162
// With validation
163
const [comment, setComment] = useState('');
164
const isValid = comment.length <= 500;
165
<Textarea
166
value={comment}
167
onValueChange={setComment}
168
error={!isValid}
169
errorMessage={!isValid ? 'Max 500 characters' : undefined}
170
/>
171
```
172
173
## Switch
174
175
```typescript { .api }
176
interface SwitchProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
177
checked?: boolean;
178
defaultChecked?: boolean;
179
onChange?: (value: boolean) => void;
180
color?: Color;
181
name?: string;
182
error?: boolean;
183
errorMessage?: string;
184
disabled?: boolean;
185
required?: boolean;
186
id?: string;
187
tooltip?: string;
188
}
189
```
190
191
**Examples:**
192
193
```typescript
194
import { Switch } from '@tremor/react';
195
196
<Switch defaultChecked={true} />
197
198
// Controlled
199
const [enabled, setEnabled] = useState(false);
200
<div className="flex items-center gap-3">
201
<Switch checked={enabled} onChange={setEnabled} color="blue" id="notifications" />
202
<label htmlFor="notifications">Enable notifications</label>
203
</div>
204
```
205
206
## Select
207
208
**Requires `<SelectItem>` children.** Use for single selection from a list.
209
210
```typescript { .api }
211
interface SelectProps {
212
value?: string;
213
name?: string;
214
defaultValue?: string;
215
onValueChange?: (value: string) => void;
216
placeholder?: string;
217
disabled?: boolean;
218
icon?: React.JSXElementConstructor<any>;
219
enableClear?: boolean;
220
required?: boolean;
221
error?: boolean;
222
errorMessage?: string;
223
children: React.ReactNode; // SelectItem components
224
}
225
226
interface SelectItemProps {
227
value: string;
228
icon?: React.ElementType;
229
children: React.ReactNode;
230
}
231
```
232
233
**Examples:**
234
235
```typescript
236
import { Select, SelectItem } from '@tremor/react';
237
238
// Basic
239
<Select placeholder="Select country...">
240
<SelectItem value="us">United States</SelectItem>
241
<SelectItem value="uk">United Kingdom</SelectItem>
242
<SelectItem value="ca">Canada</SelectItem>
243
</Select>
244
245
// Controlled with clear
246
const [country, setCountry] = useState('');
247
<Select value={country} onValueChange={setCountry} enableClear={true}>
248
<SelectItem value="us">United States</SelectItem>
249
<SelectItem value="uk">United Kingdom</SelectItem>
250
</Select>
251
252
// With validation
253
<Select error={true} errorMessage="Please select a country" required={true}>
254
<SelectItem value="us">United States</SelectItem>
255
</Select>
256
```
257
258
## MultiSelect
259
260
**Requires `<MultiSelectItem>` children.** Built-in search functionality.
261
262
```typescript { .api }
263
interface MultiSelectProps {
264
defaultValue?: string[];
265
name?: string;
266
value?: string[];
267
onValueChange?: (value: string[]) => void;
268
placeholder?: string;
269
placeholderSearch?: string;
270
disabled?: boolean;
271
icon?: React.ElementType;
272
required?: boolean;
273
error?: boolean;
274
errorMessage?: string;
275
children: React.ReactNode; // MultiSelectItem components
276
}
277
278
interface MultiSelectItemProps {
279
value: string;
280
children: React.ReactNode;
281
}
282
```
283
284
**Examples:**
285
286
```typescript
287
import { MultiSelect, MultiSelectItem } from '@tremor/react';
288
289
<MultiSelect placeholder="Select categories...">
290
<MultiSelectItem value="electronics">Electronics</MultiSelectItem>
291
<MultiSelectItem value="clothing">Clothing</MultiSelectItem>
292
</MultiSelect>
293
294
// Controlled
295
const [selected, setSelected] = useState<string[]>([]);
296
<MultiSelect
297
value={selected}
298
onValueChange={setSelected}
299
placeholderSearch="Search categories..."
300
>
301
<MultiSelectItem value="electronics">Electronics</MultiSelectItem>
302
<MultiSelectItem value="clothing">Clothing</MultiSelectItem>
303
</MultiSelect>
304
```
305
306
## SearchSelect
307
308
**Requires `<SearchSelectItem>` children.** Searchable single-select with filtering.
309
310
```typescript { .api }
311
interface SearchSelectProps {
312
defaultValue?: string;
313
name?: string;
314
searchValue?: string;
315
onSearchValueChange?: (value: string) => void;
316
value?: string;
317
onValueChange?: (value: string) => void;
318
placeholder?: string;
319
disabled?: boolean;
320
icon?: React.ElementType;
321
required?: boolean;
322
error?: boolean;
323
errorMessage?: string;
324
enableClear?: boolean;
325
children: React.ReactNode; // SearchSelectItem components
326
}
327
328
interface SearchSelectItemProps {
329
value: string;
330
icon?: React.ElementType;
331
children: React.ReactNode;
332
}
333
```
334
335
**Examples:**
336
337
```typescript
338
import { SearchSelect, SearchSelectItem } from '@tremor/react';
339
340
<SearchSelect placeholder="Search for a country..." enableClear={true}>
341
<SearchSelectItem value="us">United States</SearchSelectItem>
342
<SearchSelectItem value="uk">United Kingdom</SearchSelectItem>
343
<SearchSelectItem value="ca">Canada</SearchSelectItem>
344
{/* More items... */}
345
</SearchSelect>
346
```
347
348
## DatePicker
349
350
Date picker with calendar popup, localization, and constraints.
351
352
```typescript { .api }
353
interface DatePickerProps {
354
value?: Date;
355
defaultValue?: Date;
356
onValueChange?: (value: Date | undefined) => void;
357
minDate?: Date;
358
maxDate?: Date;
359
placeholder?: string;
360
disabled?: boolean;
361
color?: Color;
362
locale?: Locale; // from date-fns
363
enableClear?: boolean;
364
displayFormat?: string;
365
enableYearNavigation?: boolean;
366
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6; // 0 = Sunday
367
disabledDates?: Date[];
368
}
369
```
370
371
**Examples:**
372
373
```typescript
374
import { DatePicker } from '@tremor/react';
375
import { de } from 'date-fns/locale';
376
377
<DatePicker placeholder="Select a date" />
378
379
// With constraints
380
const [date, setDate] = useState<Date>();
381
<DatePicker
382
value={date}
383
onValueChange={setDate}
384
maxDate={new Date()}
385
minDate={new Date(1900, 0, 1)}
386
enableClear={true}
387
/>
388
389
// Localized
390
<DatePicker
391
locale={de}
392
weekStartsOn={1}
393
displayFormat="dd.MM.yyyy"
394
enableYearNavigation={true}
395
/>
396
```
397
398
## DateRangePicker
399
400
Date range picker with optional presets.
401
402
```typescript { .api }
403
interface DateRangePickerProps {
404
value?: { from?: Date; to?: Date; selectValue?: string };
405
defaultValue?: { from?: Date; to?: Date; selectValue?: string };
406
onValueChange?: (value: { from?: Date; to?: Date; selectValue?: string }) => void;
407
enableSelect?: boolean; // Show preset dropdown (default: true)
408
minDate?: Date;
409
maxDate?: Date;
410
placeholder?: string;
411
selectPlaceholder?: string;
412
disabled?: boolean;
413
color?: Color;
414
locale?: Locale;
415
enableClear?: boolean;
416
displayFormat?: string;
417
enableYearNavigation?: boolean;
418
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
419
disabledDates?: Date[];
420
children?: React.ReactElement[] | React.ReactElement; // DateRangePickerItem presets
421
}
422
423
interface DateRangePickerItemProps {
424
value: string;
425
from: Date;
426
to?: Date;
427
children: React.ReactNode;
428
}
429
```
430
431
**Examples:**
432
433
```typescript
434
import { DateRangePicker, DateRangePickerItem } from '@tremor/react';
435
import { subDays } from 'date-fns';
436
437
// With default presets
438
<DateRangePicker placeholder="Select date range" />
439
440
// Custom presets
441
const today = new Date();
442
<DateRangePicker>
443
<DateRangePickerItem value="last7" from={subDays(today, 7)} to={today}>
444
Last 7 days
445
</DateRangePickerItem>
446
<DateRangePickerItem value="last30" from={subDays(today, 30)} to={today}>
447
Last 30 days
448
</DateRangePickerItem>
449
</DateRangePicker>
450
451
// Calendar only (no presets)
452
<DateRangePicker enableSelect={false} />
453
```
454
455
## Tabs
456
457
Tab navigation system for content switching.
458
459
```typescript { .api }
460
interface TabGroupProps {
461
defaultIndex?: number;
462
index?: number;
463
onIndexChange?: (index: number) => void;
464
children: React.ReactNode; // TabList and TabPanels
465
}
466
467
interface TabListProps {
468
color?: Color;
469
variant?: "line" | "solid";
470
children: React.ReactElement[] | React.ReactElement; // Tab components
471
}
472
473
interface TabProps {
474
icon?: React.ElementType;
475
children: React.ReactNode;
476
}
477
478
interface TabPanelsProps {
479
children: React.ReactNode; // TabPanel components
480
}
481
482
interface TabPanelProps {
483
children: React.ReactNode;
484
}
485
```
486
487
**Examples:**
488
489
```typescript
490
import { TabGroup, TabList, Tab, TabPanels, TabPanel } from '@tremor/react';
491
import { ChartBarIcon, TableCellsIcon } from '@heroicons/react/24/outline';
492
493
// Basic
494
<TabGroup>
495
<TabList>
496
<Tab>Overview</Tab>
497
<Tab>Details</Tab>
498
</TabList>
499
<TabPanels>
500
<TabPanel><div>Overview content</div></TabPanel>
501
<TabPanel><div>Details content</div></TabPanel>
502
</TabPanels>
503
</TabGroup>
504
505
// With icons
506
<TabGroup>
507
<TabList>
508
<Tab icon={ChartBarIcon}>Chart View</Tab>
509
<Tab icon={TableCellsIcon}>Table View</Tab>
510
</TabList>
511
<TabPanels>
512
<TabPanel>{/* Chart */}</TabPanel>
513
<TabPanel>{/* Table */}</TabPanel>
514
</TabPanels>
515
</TabGroup>
516
517
// Controlled
518
const [activeTab, setActiveTab] = useState(0);
519
<TabGroup index={activeTab} onIndexChange={setActiveTab}>
520
{/* ... */}
521
</TabGroup>
522
```
523
524
## Form Validation Pattern
525
526
```typescript
527
import { Card, TextInput, Select, SelectItem, Button } from '@tremor/react';
528
529
function Form() {
530
const [name, setName] = useState('');
531
const [country, setCountry] = useState('');
532
const [errors, setErrors] = useState({ name: '', country: '' });
533
534
const validate = () => {
535
const newErrors = { name: '', country: '' };
536
if (!name) newErrors.name = 'Name is required';
537
if (!country) newErrors.country = 'Select a country';
538
setErrors(newErrors);
539
return !Object.values(newErrors).some(e => e);
540
};
541
542
return (
543
<Card className="space-y-4">
544
<TextInput
545
value={name}
546
onValueChange={setName}
547
error={!!errors.name}
548
errorMessage={errors.name}
549
/>
550
<Select
551
value={country}
552
onValueChange={setCountry}
553
error={!!errors.country}
554
errorMessage={errors.country}
555
>
556
<SelectItem value="us">United States</SelectItem>
557
</Select>
558
<Button onClick={() => validate() && console.log('Submit')}>Submit</Button>
559
</Card>
560
);
561
}
562
```
563
564
## Common Mistakes
565
566
- ❌ Forgetting `SelectItem` children for `Select` (required!)
567
- ❌ Using `onChange` instead of `onValueChange` for controlled inputs
568
- ❌ Type mismatch: `onValueChange` takes `string` for TextInput, `number` for NumberInput
569
- ❌ Forgetting `enableClear` when clearing is needed
570
- ❌ Wrong Tabs structure (must use `TabGroup > TabList + TabPanels`)
571
572
## See Also
573
574
- [Common Props Reference](./common-props.md) for shared input props
575
- [Types Reference](./types.md) for TypeScript types
576