A restrained, rounded text field with support for icons and add-ons. Built on the native HTML input element with clear interaction and validation states.
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| value | string | Yes | - | Input value (controlled) |
| onValueChange | (value: string) => void | No | - | Callback when value changes |
| placeholder | string | No | - | Placeholder text |
| addOn | ReactNode | No | - | Element displayed inside the input (typically an icon) |
| addOnPosition | "start" | "end" | No | "start" | Add-on placement |
| size | Size | No | "medium" | Font size (matches Button sizing) |
| padding | Padding | No | "medium" | Internal padding |
| gap | Gap | No | "small" | Space between add-on and input |
| disabled | boolean | No | false | Disables the input |
| type | string | No | "text" | HTML input type |
| jss | JSS | No | - | Custom styles for the input element |
| jssRoot | JSS | No | - | Custom styles for the container |
Also accepts all standard HTML input attributes (name, id, autoFocus, maxLength, etc.).
The resting field uses a flat surface and a subtle rounded boundary. It has no elevation shadow; focus and validation states provide the stronger visual emphasis.
const [name, setName] = useState("");
<TextInput
value={name}
placeholder="Enter your name"
onValueChange={setName}
/>;
Add icons to provide visual context. Icons can be placed at the start or end of the input.
// Icon at start (default)
<TextInput
value={email}
addOn={<Icon icon="mail" color="primary" size="medium" />}
onValueChange={setEmail}
/>
// Icon at end
<TextInput
value={password}
addOn={<Icon icon="lock" color="secondary" size="medium" />}
addOnPosition="end"
type="password"
onValueChange={setPassword}
/>
The size prop controls font size and matches the Button component's sizing system.
<TextInput size="small" ... />
<TextInput size="medium" ... /> // default
<TextInput size="large" ... />
The boundary becomes stronger on hover and a crisp two-pixel outer ring marks keyboard focus. Disabled fields use a muted surface. Set aria-invalid="true" to use the negative validation boundary and text color.
<TextInput value="Cannot edit" disabled onValueChange={() => {}} />
<TextInput
value={email}
aria-invalid={hasError}
aria-describedby={hasError ? "email-error" : undefined}
onValueChange={setEmail}
/>
TextInput works with standard form patterns and can be used with refs for form libraries.
import { useRef } from "react";
function Form() {
const inputRef = useRef < HTMLInputElement > null;
const [value, setValue] = useState("");
return (
<form onSubmit={handleSubmit}>
<TextInput
ref={inputRef}
name="email"
type="email"
value={value}
placeholder="Email address"
onValueChange={setValue}
addOn={<Icon icon="mail" color="primary" size="medium" />}
/>
</form>
);
}
<label htmlFor="email">Email</label>
<TextInput
id="email"
name="email"
type="email"
value={email}
onValueChange={setEmail}
/>