TextInput

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.

Props

PropTypeRequiredDefaultDescription
valuestringYes-Input value (controlled)
onValueChange(value: string) => voidNo-Callback when value changes
placeholderstringNo-Placeholder text
addOnReactNodeNo-Element displayed inside the input (typically an icon)
addOnPosition"start" | "end"No"start"Add-on placement
sizeSizeNo"medium"Font size (matches Button sizing)
paddingPaddingNo"medium"Internal padding
gapGapNo"small"Space between add-on and input
disabledbooleanNofalseDisables the input
typestringNo"text"HTML input type
jssJSSNo-Custom styles for the input element
jssRootJSSNo-Custom styles for the container

Also accepts all standard HTML input attributes (name, id, autoFocus, maxLength, etc.).

Basic usage

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}
/>;

With add-on

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}
/>

Sizes

The size prop controls font size and matches the Button component's sizing system.

<TextInput size="small" ... />
<TextInput size="medium" ... />  // default
<TextInput size="large" ... />

States

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}
/>

Form integration

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>
  );
}

Accessibility

  • Uses native <input> element for full accessibility support
  • Uses a visible two-pixel keyboard focus indicator
  • Supports native disabled, readOnly, and aria-invalid states
  • Placeholder text is styled with sufficient contrast
  • Works with form labels using id and htmlFor
<label htmlFor="email">Email</label>
<TextInput
  id="email"
  name="email"
  type="email"
  value={email}
  onValueChange={setEmail}
/>