Theme UI provides a comprehensive set of form components with consistent styling and theme integration.
Components
import {
Input,
Select,
Textarea,
Label,
Checkbox,
Radio,
Switch,
Slider,
} from 'theme-ui'
Text input component with theme variants.
<Input placeholder="Enter text" />
Input variant from theme.forms.<Input variant="input" />
<Input variant="search" />
autofillBackgroundColor
string
default:"'background'"
Background color for autofilled inputs. Maps to theme colors.<Input autofillBackgroundColor="muted" />
HTML input type (text, email, password, etc.).<Input type="email" placeholder="Email" />
<Input type="password" placeholder="Password" />
Examples
{/* Basic input */}
<Input placeholder="Your name" />
{/* Email input */}
<Input type="email" placeholder="[email protected]" />
{/* With label */}
<Label>
Email
<Input type="email" />
</Label>
{/* Custom styling */}
<Input
sx={{
borderColor: 'primary',
'&:focus': {
borderColor: 'secondary',
outline: 'none',
},
}}
/>
Dropdown select component with custom arrow indicator.
<Select>
<option>Option 1</option>
<option>Option 2</option>
</Select>
Select variant from theme.forms.
Custom arrow element to replace the default down arrow.<Select arrow={<CustomArrow />}>
<option>Option</option>
</Select>
Examples
{/* Basic select */}
<Select>
<option>Choose one</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</Select>
{/* With label */}
<Label>
Country
<Select>
<option>United States</option>
<option>Canada</option>
<option>Mexico</option>
</Select>
</Label>
Textarea
Multi-line text input component.
<Textarea placeholder="Enter longer text" />
variant
string
default:"'textarea'"
Textarea variant from theme.forms.
Number of visible text rows.
Examples
{/* Basic textarea */}
<Textarea placeholder="Your message" />
{/* With label */}
<Label>
Message
<Textarea rows={4} />
</Label>
{/* Custom height */}
<Textarea sx={{ minHeight: 200 }} />
Form label component for accessibility.
<Label>
Field Name
<Input />
</Label>
Associates label with an input by ID.<Label htmlFor="email">Email</Label>
<Input id="email" />
Label variant from theme.forms.
Examples
{/* Wrapping input */}
<Label>
Username
<Input />
</Label>
{/* Using htmlFor */}
<Label htmlFor="email">Email Address</Label>
<Input id="email" type="email" />
{/* Inline label */}
<Label sx={{ display: 'inline-flex', alignItems: 'center' }}>
<Checkbox />
I agree to terms
</Label>
Checkbox
Checkbox input with custom styled appearance.
<Label>
<Checkbox />
Accept terms
</Label>
variant
string
default:"'checkbox'"
Checkbox variant from theme.forms.
Controlled checked state.
Default checked state (uncontrolled).
Examples
{/* Basic checkbox */}
<Label>
<Checkbox /> Subscribe to newsletter
</Label>
{/* Controlled checkbox */}
<Label>
<Checkbox checked={isChecked} onChange={e => setIsChecked(e.target.checked)} />
Toggle me
</Label>
{/* Multiple checkboxes */}
<Box>
<Label><Checkbox /> Option 1</Label>
<Label><Checkbox /> Option 2</Label>
<Label><Checkbox /> Option 3</Label>
</Box>
Radio button input with custom styled appearance.
<Label>
<Radio name="group" />
Option 1
</Label>
Radio group name. Required to link radio buttons together.
Radio variant from theme.forms.
Controlled checked state.
Examples
{/* Radio group */}
<Box>
<Label>
<Radio name="plan" value="basic" />
Basic Plan
</Label>
<Label>
<Radio name="plan" value="pro" />
Pro Plan
</Label>
<Label>
<Radio name="plan" value="enterprise" />
Enterprise
</Label>
</Box>
{/* Controlled radio */}
<Label>
<Radio
name="size"
value="large"
checked={size === 'large'}
onChange={e => setSize(e.target.value)}
/>
Large
</Label>
Toggle switch component for binary choices.
<Switch label="Enable notifications" />
Label text for the switch.<Switch label="Dark mode" />
Switch variant from theme.forms.
Controlled checked state.
Examples
{/* Basic switch */}
<Switch label="Enable feature" />
{/* Controlled switch */}
<Switch
label="Dark mode"
checked={darkMode}
onChange={e => setDarkMode(e.target.checked)}
/>
{/* Disabled switch */}
<Switch label="Feature disabled" disabled />
Range slider input component.
Slider variant from theme.forms.
Default value (uncontrolled).
Examples
{/* Basic slider */}
<Label>
Volume
<Slider />
</Label>
{/* Custom range */}
<Slider min={0} max={10} step={0.5} />
{/* Controlled slider */}
<Box>
<Label>Brightness: {brightness}%</Label>
<Slider
value={brightness}
onChange={e => setBrightness(e.target.value)}
/>
</Box>
{/* With display value */}
<Box>
<Flex sx={{ justifyContent: 'space-between', mb: 2 }}>
<Text>Price</Text>
<Text>${price}</Text>
</Flex>
<Slider
min={0}
max={1000}
value={price}
onChange={e => setPrice(e.target.value)}
/>
</Box>
Form Example
Complete form example using multiple components:
<Box as="form" onSubmit={handleSubmit}>
<Label htmlFor="name">
Name
<Input id="name" name="name" required />
</Label>
<Label htmlFor="email">
Email
<Input id="email" name="email" type="email" required />
</Label>
<Label htmlFor="country">
Country
<Select id="country" name="country">
<option>United States</option>
<option>Canada</option>
<option>Other</option>
</Select>
</Label>
<Label htmlFor="message">
Message
<Textarea id="message" name="message" rows={4} />
</Label>
<Label>
<Checkbox name="newsletter" />
Subscribe to newsletter
</Label>
<Label>
<Switch label="Send me updates" name="updates" />
</Label>
<Button type="submit">Submit</Button>
</Box>