TextInput Component

A single-line text input component that integrates with Reef's container system for consistent border radius math and status coloring. Supports input masks, validation with Effect schemas, and various presets.

Usage

Basic Input

<TextInput placeholder="Enter text..." />

With Label

<TextInput label="Username" placeholder="Enter username" />

Controlled Input

Current value: ""

const [value, setValue] = createSignal("");

<TextInput
  label="Controlled"
  value={value}
  onValue={setValue}
  placeholder="Type something..."
/>

Disabled State

<TextInput label="Disabled" placeholder="Cannot edit" disabled />

With Prefix

Fixed non-editable text at the start. Smart paste: if pasted content contains the prefix, it's automatically stripped.

@
<TextInput label="Username" prefix="@" placeholder="username" />

With Suffix

@company.com
<TextInput label="Email" suffix="@company.com" placeholder="username" />

With Slots

Slots allow custom content at the start or end of the input. Must be passed as functions to avoid hydration issues.

🔍
<TextInput
  label="Search"
  slotStart={() => <Icon icon="search" />}
  placeholder="Search..."
/>

With Error Message

When an error message is provided, the input automatically switches to danger status.

Please enter a valid email address
<TextInput
  label="Email"
  placeholder="Enter email..."
  errorMessage="Please enter a valid email address"
/>

Label Positions

Labels can be positioned above, below, before, or after the input.

<TextInput label="Above" labelPosition="above" />
<TextInput label="Below" labelPosition="below" />
<TextInput label="Before" labelPosition="before" />
<TextInput label="After" labelPosition="after" />

Validation

Use a validate function for validation and transformation. When allowInvalid is false (default), invalid keystrokes are prevented. When true, invalid input is allowed but shows an error.

With Validation (allowInvalid: true)

const positiveIntValidator: ValidateFn<number> = (value) => {
  const num = Number(value);
  if (Number.isNaN(num)) return { valid: false, error: "Must be a number" };
  if (!Number.isInteger(num)) return { valid: false, error: "Must be an integer" };
  if (num <= 0) return { valid: false, error: "Must be positive" };
  return { valid: true, value: num };
};

<TextInput
  label="Age"
  validate={positiveIntValidator}
  allowInvalid
/>

Presets

TextInput provides preset variants for common use cases.

TextInput.Password

Password input with visibility toggle button.

<TextInput.Password label="Password" placeholder="Enter password..." />

TextInput.Search

Search input with a search icon.

🔍
<TextInput.Search label="Search" placeholder="Search..." />

TextInput.Email

Email input with appropriate autocomplete.

<TextInput.Email label="Email" placeholder="you@example.com" />

TextInput.URL

URL input with optional protocol prefix.

https://
<TextInput.URL label="Website" protocol="https://" placeholder="example.com" />

TextInput.Number

Number input with increment/decrement controls. Supports min, max, step, and scale (decimal places). Use arrow keys to increment/decrement.

Current value: 0

<TextInput.Number label="Quantity" min={0} max={100} step={1} />

TextInput.Currency

Currency input with currency symbol prefix and 2 decimal places.

$
<TextInput.Currency label="Price" currency="USD" />

TextInput.Phone

Phone number input with pattern mask.

<TextInput.Phone label="Phone" placeholder="(555) 123-4567" />

TextInput.SSN

US Social Security Number with automatic formatting (###-##-####).

<TextInput.SSN label="SSN" />

Mask System

TextInput supports three types of masks for formatting input:

PatternMask

For fixed-length structured inputs. DSL: # = digit, A = letter, * = any.

// Phone number
mask={{ type: "pattern", pattern: "(###) ###-####" }}

// SSN
mask={{ type: "pattern", pattern: "###-##-####" }}

NumberMask

For numeric inputs with locale-aware formatting. Supports min, max, scale (decimal places), and step.

mask={{ type: "number", min: 0, max: 100, scale: 2 }}

TextMask

For variable-length inputs with validation. Supports pattern (regex), minLength, maxLength, and redact.

mask={{ type: "text", maxLength: 50, pattern: /^[a-z]+$/ }}

Props

NameTypeDefaultDescription
valueAccessor<string>undefined

Controlled value accessor for the input

onValue(value: string) => voidundefined

Callback when the input value changes

onRawValue(value: string) => voidundefined

Callback when the raw (unmasked) value changes

onTypedValue(value: T) => voidundefined

Callback when schema-transformed value changes

placeholderstringundefined

Placeholder text shown when the input is empty

disabledbooleanfalse

Disables the input when true

labelstringundefined

Label text displayed above the input

prefixstringundefined

Fixed non-editable prefix (e.g., 'user_')

suffixstringundefined

Fixed non-editable suffix (e.g., '@company.com')

slotStart() => JSX.Elementundefined

Function returning content for the start of the input

slotEnd() => JSX.Elementundefined

Function returning content for the end of the input

labelPosition"above" | "below" | "before" | "after""above"

Label placement relative to input

errorMessagestringundefined

Error message displayed next to label (auto-switches status to danger)

validateValidateFn<T>undefined

Validation function for input validation and transformation

allowInvalidbooleanfalse

If true, allows invalid input and shows error; if false, prevents invalid keystrokes

maskPatternMask | NumberMask | TextMaskundefined

Input mask for formatting

autocompletestringundefined

HTML autocomplete attribute for browser autofill

type"text" | "password" | "email" | "url" | "tel" | "search""text"

HTML input type

statusStatusfrom ContainerContext or 'neutral'

Status for color theming

stylesStyleXStylesundefined

Additional StyleX styles to apply