Tremor React is a comprehensive React component library built on Tailwind CSS providing 60+ components for building data visualizations, charts, and analytical dashboards.
Form controls and interactive elements.
⚠️ All inputs share common input props: error, errorMessage, disabled, placeholder, icon.
| Component | Use Case | Key Props |
|---|---|---|
| Button | Actions, submissions | variant, loading, icon, iconPosition |
| TextInput | Single-line text | Standard input props + type |
| NumberInput | Numeric values | enableStepper, step, min, max, onSubmit |
| Textarea | Multi-line text | autoHeight, rows |
| Switch | Boolean toggle | checked, onChange, color |
| Select | Single selection dropdown | enableClear + requires <SelectItem> children |
| MultiSelect | Multiple selections | placeholderSearch + requires <MultiSelectItem> |
| SearchSelect | Searchable single select | searchValue, onSearchValueChange + <SearchSelectItem> |
| DatePicker | Date selection | minDate, maxDate, locale, weekStartsOn |
| DateRangePicker | Date range | enableSelect + optional <DateRangePickerItem> presets |
| Tabs | Content switching | Use TabGroup/TabList/Tab/TabPanels/TabPanel |
All inputs support both modes (controlled recommended):
// Controlled (recommended)
const [value, setValue] = useState('');
<TextInput value={value} onValueChange={setValue} />
// Uncontrolled
<TextInput defaultValue="initial" />interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
icon?: React.ElementType;
iconPosition?: "left" | "right";
size?: Size;
color?: Color;
variant?: "primary" | "secondary" | "light";
disabled?: boolean;
loading?: boolean;
loadingText?: string;
tooltip?: string;
}Examples:
import { Button } from '@tremor/react';
import { PlusIcon, DownloadIcon } from '@heroicons/react/24/outline';
<Button>Click me</Button>
<Button icon={PlusIcon} variant="primary" color="blue">Add Item</Button>
<Button loading loadingText="Saving...">Save</Button>
<Button icon={DownloadIcon} iconPosition="right" variant="secondary">Export</Button>interface TextInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
defaultValue?: string;
value?: string;
onValueChange?: (value: string) => void;
icon?: React.ElementType | React.JSXElementConstructor<any>;
error?: boolean;
errorMessage?: string;
disabled?: boolean;
// Plus all standard HTML input props: type, placeholder, pattern, etc.
}Examples:
import { TextInput } from '@tremor/react';
import { MagnifyingGlassIcon, EnvelopeIcon } from '@heroicons/react/24/outline';
// With icon
<TextInput icon={MagnifyingGlassIcon} placeholder="Search..." />
// With validation
function EmailInput() {
const [email, setEmail] = useState('');
const [error, setError] = useState('');
return (
<TextInput
icon={EnvelopeIcon}
type="email"
value={email}
onValueChange={(v) => {
setEmail(v);
setError(v && !v.includes('@') ? 'Invalid email' : '');
}}
error={!!error}
errorMessage={error}
/>
);
}interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'> {
value?: number;
defaultValue?: number;
onValueChange?: (value: number) => void;
step?: string | number;
enableStepper?: boolean; // Show +/- buttons
onSubmit?: (value: number) => void;
min?: number;
max?: number;
icon?: React.ElementType;
error?: boolean;
errorMessage?: string;
disabled?: boolean;
}Examples:
import { NumberInput } from '@tremor/react';
<NumberInput placeholder="Enter amount" min={0} max={1000} />
<NumberInput defaultValue={10} step={5} enableStepper={true} />
// Controlled with decimals
const [price, setPrice] = useState(19.99);
<NumberInput value={price} onValueChange={setPrice} step={0.01} enableStepper={true} />interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
defaultValue?: string | number;
value?: string | number;
error?: boolean;
errorMessage?: string;
disabled?: boolean;
autoHeight?: boolean; // Automatically adjust height to content
onValueChange?: (value: any) => void;
}Examples:
import { Textarea } from '@tremor/react';
<Textarea placeholder="Enter your message..." rows={4} />
<Textarea autoHeight={true} placeholder="Auto-expanding textarea" />
// With validation
const [comment, setComment] = useState('');
const isValid = comment.length <= 500;
<Textarea
value={comment}
onValueChange={setComment}
error={!isValid}
errorMessage={!isValid ? 'Max 500 characters' : undefined}
/>interface SwitchProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
checked?: boolean;
defaultChecked?: boolean;
onChange?: (value: boolean) => void;
color?: Color;
name?: string;
error?: boolean;
errorMessage?: string;
disabled?: boolean;
required?: boolean;
id?: string;
tooltip?: string;
}Examples:
import { Switch } from '@tremor/react';
<Switch defaultChecked={true} />
// Controlled
const [enabled, setEnabled] = useState(false);
<div className="flex items-center gap-3">
<Switch checked={enabled} onChange={setEnabled} color="blue" id="notifications" />
<label htmlFor="notifications">Enable notifications</label>
</div>Requires <SelectItem> children. Use for single selection from a list.
interface SelectProps {
value?: string;
name?: string;
defaultValue?: string;
onValueChange?: (value: string) => void;
placeholder?: string;
disabled?: boolean;
icon?: React.JSXElementConstructor<any>;
enableClear?: boolean;
required?: boolean;
error?: boolean;
errorMessage?: string;
children: React.ReactNode; // SelectItem components
}
interface SelectItemProps {
value: string;
icon?: React.ElementType;
children: React.ReactNode;
}Examples:
import { Select, SelectItem } from '@tremor/react';
// Basic
<Select placeholder="Select country...">
<SelectItem value="us">United States</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
</Select>
// Controlled with clear
const [country, setCountry] = useState('');
<Select value={country} onValueChange={setCountry} enableClear={true}>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
</Select>
// With validation
<Select error={true} errorMessage="Please select a country" required={true}>
<SelectItem value="us">United States</SelectItem>
</Select>Requires <MultiSelectItem> children. Built-in search functionality.
interface MultiSelectProps {
defaultValue?: string[];
name?: string;
value?: string[];
onValueChange?: (value: string[]) => void;
placeholder?: string;
placeholderSearch?: string;
disabled?: boolean;
icon?: React.ElementType;
required?: boolean;
error?: boolean;
errorMessage?: string;
children: React.ReactNode; // MultiSelectItem components
}
interface MultiSelectItemProps {
value: string;
children: React.ReactNode;
}Examples:
import { MultiSelect, MultiSelectItem } from '@tremor/react';
<MultiSelect placeholder="Select categories...">
<MultiSelectItem value="electronics">Electronics</MultiSelectItem>
<MultiSelectItem value="clothing">Clothing</MultiSelectItem>
</MultiSelect>
// Controlled
const [selected, setSelected] = useState<string[]>([]);
<MultiSelect
value={selected}
onValueChange={setSelected}
placeholderSearch="Search categories..."
>
<MultiSelectItem value="electronics">Electronics</MultiSelectItem>
<MultiSelectItem value="clothing">Clothing</MultiSelectItem>
</MultiSelect>Requires <SearchSelectItem> children. Searchable single-select with filtering.
interface SearchSelectProps {
defaultValue?: string;
name?: string;
searchValue?: string;
onSearchValueChange?: (value: string) => void;
value?: string;
onValueChange?: (value: string) => void;
placeholder?: string;
disabled?: boolean;
icon?: React.ElementType;
required?: boolean;
error?: boolean;
errorMessage?: string;
enableClear?: boolean;
children: React.ReactNode; // SearchSelectItem components
}
interface SearchSelectItemProps {
value: string;
icon?: React.ElementType;
children: React.ReactNode;
}Examples:
import { SearchSelect, SearchSelectItem } from '@tremor/react';
<SearchSelect placeholder="Search for a country..." enableClear={true}>
<SearchSelectItem value="us">United States</SearchSelectItem>
<SearchSelectItem value="uk">United Kingdom</SearchSelectItem>
<SearchSelectItem value="ca">Canada</SearchSelectItem>
{/* More items... */}
</SearchSelect>Date picker with calendar popup, localization, and constraints.
interface DatePickerProps {
value?: Date;
defaultValue?: Date;
onValueChange?: (value: Date | undefined) => void;
minDate?: Date;
maxDate?: Date;
placeholder?: string;
disabled?: boolean;
color?: Color;
locale?: Locale; // from date-fns
enableClear?: boolean;
displayFormat?: string;
enableYearNavigation?: boolean;
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6; // 0 = Sunday
disabledDates?: Date[];
}Examples:
import { DatePicker } from '@tremor/react';
import { de } from 'date-fns/locale';
<DatePicker placeholder="Select a date" />
// With constraints
const [date, setDate] = useState<Date>();
<DatePicker
value={date}
onValueChange={setDate}
maxDate={new Date()}
minDate={new Date(1900, 0, 1)}
enableClear={true}
/>
// Localized
<DatePicker
locale={de}
weekStartsOn={1}
displayFormat="dd.MM.yyyy"
enableYearNavigation={true}
/>Date range picker with optional presets.
interface DateRangePickerProps {
value?: { from?: Date; to?: Date; selectValue?: string };
defaultValue?: { from?: Date; to?: Date; selectValue?: string };
onValueChange?: (value: { from?: Date; to?: Date; selectValue?: string }) => void;
enableSelect?: boolean; // Show preset dropdown (default: true)
minDate?: Date;
maxDate?: Date;
placeholder?: string;
selectPlaceholder?: string;
disabled?: boolean;
color?: Color;
locale?: Locale;
enableClear?: boolean;
displayFormat?: string;
enableYearNavigation?: boolean;
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
disabledDates?: Date[];
children?: React.ReactElement[] | React.ReactElement; // DateRangePickerItem presets
}
interface DateRangePickerItemProps {
value: string;
from: Date;
to?: Date;
children: React.ReactNode;
}Examples:
import { DateRangePicker, DateRangePickerItem } from '@tremor/react';
import { subDays } from 'date-fns';
// With default presets
<DateRangePicker placeholder="Select date range" />
// Custom presets
const today = new Date();
<DateRangePicker>
<DateRangePickerItem value="last7" from={subDays(today, 7)} to={today}>
Last 7 days
</DateRangePickerItem>
<DateRangePickerItem value="last30" from={subDays(today, 30)} to={today}>
Last 30 days
</DateRangePickerItem>
</DateRangePicker>
// Calendar only (no presets)
<DateRangePicker enableSelect={false} />Tab navigation system for content switching.
interface TabGroupProps {
defaultIndex?: number;
index?: number;
onIndexChange?: (index: number) => void;
children: React.ReactNode; // TabList and TabPanels
}
interface TabListProps {
color?: Color;
variant?: "line" | "solid";
children: React.ReactElement[] | React.ReactElement; // Tab components
}
interface TabProps {
icon?: React.ElementType;
children: React.ReactNode;
}
interface TabPanelsProps {
children: React.ReactNode; // TabPanel components
}
interface TabPanelProps {
children: React.ReactNode;
}Examples:
import { TabGroup, TabList, Tab, TabPanels, TabPanel } from '@tremor/react';
import { ChartBarIcon, TableCellsIcon } from '@heroicons/react/24/outline';
// Basic
<TabGroup>
<TabList>
<Tab>Overview</Tab>
<Tab>Details</Tab>
</TabList>
<TabPanels>
<TabPanel><div>Overview content</div></TabPanel>
<TabPanel><div>Details content</div></TabPanel>
</TabPanels>
</TabGroup>
// With icons
<TabGroup>
<TabList>
<Tab icon={ChartBarIcon}>Chart View</Tab>
<Tab icon={TableCellsIcon}>Table View</Tab>
</TabList>
<TabPanels>
<TabPanel>{/* Chart */}</TabPanel>
<TabPanel>{/* Table */}</TabPanel>
</TabPanels>
</TabGroup>
// Controlled
const [activeTab, setActiveTab] = useState(0);
<TabGroup index={activeTab} onIndexChange={setActiveTab}>
{/* ... */}
</TabGroup>import { Card, TextInput, Select, SelectItem, Button } from '@tremor/react';
function Form() {
const [name, setName] = useState('');
const [country, setCountry] = useState('');
const [errors, setErrors] = useState({ name: '', country: '' });
const validate = () => {
const newErrors = { name: '', country: '' };
if (!name) newErrors.name = 'Name is required';
if (!country) newErrors.country = 'Select a country';
setErrors(newErrors);
return !Object.values(newErrors).some(e => e);
};
return (
<Card className="space-y-4">
<TextInput
value={name}
onValueChange={setName}
error={!!errors.name}
errorMessage={errors.name}
/>
<Select
value={country}
onValueChange={setCountry}
error={!!errors.country}
errorMessage={errors.country}
>
<SelectItem value="us">United States</SelectItem>
</Select>
<Button onClick={() => validate() && console.log('Submit')}>Submit</Button>
</Card>
);
}SelectItem children for Select (required!)onChange instead of onValueChange for controlled inputsonValueChange takes string for TextInput, number for NumberInputenableClear when clearing is neededTabGroup > TabList + TabPanels)Install with Tessl CLI
npx tessl i tessl/npm-tremor--react