or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

chart-elements.mdcommon-props.mdicon-elements.mdindex.mdinput-elements.mdlayout-elements.mdlist-elements.mdtext-elements.mdtypes.mdvisualization-elements.md

input-elements.mddocs/

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