TextInput
A theme-aware text input primitive. Supports controlled and uncontrolled usage, multiline (textarea), error and disabled states, and all standard form attributes.
A theme-aware text input primitive. Supports controlled and uncontrolled usage, multiline (textarea), error and disabled states, and all standard form attributes.
Architecture: TextInputRoot is a styled <div> that owns the visible border and focus ring. The native <input> (or <textarea>) sits inside it with a transparent background, so the root border appears as the field border. This makes it easy to add prefix/suffix adornments later.
Examples
Default
<TextInput resize={false} placeholder="Enter a value..." />
States
Default
Disabled
Disabled + value
Error
Error + value
<Flex flexDirection="column" gap={2} maxWidth="360px"> {( [ { label: 'Default', props: { placeholder: 'Default' } }, { label: 'Disabled', props: { placeholder: 'Disabled', disabled: true } }, { label: 'Disabled + value', props: { value: 'Cannot edit', disabled: true, onChange: () => {} }, }, { label: 'Error', props: { placeholder: 'Invalid field', error: true } }, { label: 'Error + value', props: { value: 'bad@', error: true, onChange: () => {} }, }, ] as const ).map(({ label, props }) => ( <Flex key={label} flexDirection="row" alignItems="center" gap={3}> <Typography variant="caption" color="secondary" width="8rem" flexShrink={0} m={0}> {label} </Typography> <TextInput color="primary" fullWidth {...props} /> </Flex> ))} </Flex>
Variants
NormalDisabledError
outlined
underline
text
<Flex flexDirection="column" gap={3} maxWidth="560px"> <Flex flexDirection="row" gap={2} mb={1}> {(['Normal', 'Disabled', 'Error'] as const).map((h) => ( <Typography key={h} variant="caption" color="secondary" flex={1} m={0}> {h} </Typography> ))} </Flex> {(['outlined', 'underline', 'text'] as const).map((variant) => ( <Flex key={variant} flexDirection="column" gap={1}> <Typography variant="caption" color="secondary" m={0}> {variant} </Typography> <Flex flexDirection="row" gap={2} alignItems="center"> <TextInput variant={variant} color="primary" placeholder="Normal" fullWidth /> <TextInput variant={variant} color="primary" placeholder="Disabled" disabled fullWidth /> <TextInput variant={variant} color="primary" placeholder="Error" error fullWidth /> </Flex> </Flex> ))} </Flex>
Colors
Default (click)DisabledError
primary
secondary
success
error
info
warning
<Flex flexDirection="column" gap={3} maxWidth="560px"> <Flex flexDirection="row" gap={2} mb={1}> {(['Default (click)', 'Disabled', 'Error'] as const).map((h) => ( <Typography key={h} variant="caption" color="secondary" flex={1} m={0}> {h} </Typography> ))} </Flex> {(['primary', 'secondary', 'success', 'error', 'info', 'warning'] as const).map((color) => ( <Flex key={color} flexDirection="column" gap={1}> <Typography variant="caption" color="secondary" m={0}> {color} </Typography> <Flex flexDirection="row" gap={2}> <TextInput variant="outlined" color={color} placeholder="Click to focus" fullWidth /> <TextInput variant="outlined" color={color} placeholder="Disabled" disabled fullWidth /> <TextInput variant="outlined" color={color} placeholder="Error" error fullWidth /> </Flex> </Flex> ))} </Flex>
Multiline - Auto-grow
Grows with content - no fixed height
<Flex flexDirection="column" gap={1} maxWidth="480px"> <Typography variant="caption" color="secondary" m={0}> Grows with content - no fixed height </Typography> <TextInput multiline resize fullWidth placeholder="Start typing... the field expands as you write." /> </Flex>
Multiline - Fixed rows
Fixed to 4 rows - scrolls when content overflows
<Flex flexDirection="column" gap={1} maxWidth="480px"> <Typography variant="caption" color="secondary" m={0}> Fixed to 4 rows - scrolls when content overflows </Typography> <TextInput rows={4} fullWidth placeholder="Write something..." /> </Flex>
Full Width
const args: Partial<TextInputProps> = {} <Flex width="100%" maxWidth="480px"> <TextInput {...args} fullWidth placeholder="Full-width input..." /> </Flex>
Types
text
email
password
number
search
url
<Flex flexDirection="column" gap={2} maxWidth="360px"> {( [ { type: 'text', placeholder: 'Text' }, { type: 'email', placeholder: '[email protected]' }, { type: 'password', placeholder: 'Password' }, { type: 'number', placeholder: '0' }, { type: 'search', placeholder: 'Search...' }, { type: 'url', placeholder: 'https://' }, ] as const ).map(({ type, placeholder }) => ( <Flex key={type} flexDirection="row" alignItems="center" gap={3}> <Typography variant="caption" color="secondary" width="5rem" flexShrink={0} m={0}> {type} </Typography> <TextInput type={type} placeholder={placeholder} fullWidth /> </Flex> ))} </Flex>