Text input
Fields the user types a value into.
TextInput #
Text field. Every other attribute (id, name, autocomplete, aria-*, …) lands on the <input>.
function Example() {
const name = signal("");
return (
<TextInput
aria-label="Full name"
placeholder="Ada Lovelace"
value={name()}
onInput={(e) => name.set((e.target as HTMLInputElement).value)}
/>
);
}| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
disabled | boolean | Disables the field. | ||
invalid | boolean | Marks the value invalid (aria-invalid and error styling). | ||
name | string | Field name submitted with the form. | ||
onBlur | (e: FocusEvent) => void | Called when the field loses focus. | ||
onFocus | (e: FocusEvent) => void | Called when the field gains focus. | ||
onInput | (e: InputEvent) => void | Called on every edit; read e.target.value. | ||
onKeyDown | (e: KeyboardEvent) => void | Called on key presses. | ||
placeholder | string | Hint shown while empty. | ||
type | string | "text" | Native input type (text, email, url, tel, …). | |
value | string | "" | Current text (controlled; update it from onInput). |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
TextArea #
Multi-line text field.
function Example() {
const message = signal("");
return (
<TextArea
aria-label="Message"
rows={3}
placeholder="Tell us what happened…"
value={message()}
onInput={(e) => message.set((e.target as HTMLInputElement).value)}
/>
);
}| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
disabled | boolean | Disables the field. | ||
invalid | boolean | Marks the value invalid (aria-invalid and error styling). | ||
name | string | Field name submitted with the form. | ||
onBlur | (e: FocusEvent) => void | Called when the field loses focus. | ||
onInput | (e: InputEvent) => void | Called on every edit; read e.target.value. | ||
placeholder | string | Hint shown while empty. | ||
rows | number | Visible text lines. | ||
value | string | "" | Current text (controlled; update it from onInput). |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
Number input #
Numbers and quantities with steppers.
NumberInput #
Numeric field. Typing keeps a free-form draft (so 15 can be typed with min=10); values commit when in range and clamp on blur / Enter / step. Results are rounded to the precision of step (no 0.30000000000000004). The <input> is the host (class, style, id, aria-* land on it); classes.root styles the wrapper.
function Example() {
const seats = signal(5);
return (
<NumberInput aria-label="Seats" min={1} max={50} value={seats()} onChange={seats.set} />
);
}Slots: root decrement increment input
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
onChange | (value: number) => void | yes | Called with the new number (never NaN). | |
value | number | yes | Current value (controlled). | |
decrementLabel | string | "Decrease" | Accessible labels for the step buttons. | |
disabled | boolean | Disables the field and its buttons. | ||
incrementLabel | string | "Increase" | Accessible name of the + button. | |
invalid | boolean | Marks the value invalid (aria-invalid and error styling). | ||
max | number | Highest value; typing above it is clamped on blur. | ||
min | number | 0 | Lowest value; typing below it is clamped on blur. | |
name | string | Field name submitted with the form. | ||
step | number | Amount the − / + buttons and arrow keys change the value by. |
QuantityInput #
− value + stepper.
function Example() {
const quantity = signal(2);
return <QuantityInput min={1} max={10} value={quantity()} onChange={quantity.set} />;
}Slots: root button value
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
onChange | (value: number) => void | yes | Called with the new quantity. | |
value | number | yes | Current quantity (controlled). | |
disabled | boolean | Disables both buttons. | ||
label | string | "Quantity" | Accessible name for the stepper group (default "Quantity"). | |
max | number | 99 | Highest quantity (the + button disables there). | |
min | number | 1 | Lowest quantity (the − button disables there). |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
Password #
Password entry and strength feedback.
PasswordInput #
Password field with visibility toggle. The <input> is the host (class, id, autocomplete, aria-* land on it); classes.root styles the wrapper.
function Example() {
const password = signal("");
return <PasswordInput aria-label="Password" value={password()} onChange={password.set} />;
}Slots: root input toggle
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
onChange | (value: string) => void | yes | Called with the new password on every edit. | |
value | string | yes | Current password (controlled). | |
disabled | boolean | Disables the field. | ||
hideLabel | string | "Hide password" | Accessible name of the reveal button while shown. | |
invalid | boolean | Marks the value invalid (aria-invalid and error styling). | ||
name | string | Field name submitted with the form. | ||
placeholder | string | Hint shown while empty. | ||
showLabel | string | "Show password" | Accessible name of the reveal button while hidden. |
PasswordStrength #
Four-bar strength meter.
<PasswordStrength password="correct horse" />Slots: root bar bars label
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
password | string | yes | "" | The password to rate (strength bar and hints). |
labels | [string, string, string, string, string] | Override the five labels (score 0–4). |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
SearchInput #
Search field with clear button. The <input> is the host; classes.root styles the wrapper.
function Example() {
const query = signal("");
return (
<SearchInput
aria-label="Search projects"
placeholder="Search projects"
value={query()}
onChange={query.set}
/>
);
}Slots: root clear icon input
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
onChange | (value: string) => void | yes | Called with the new query on every edit (and with "" when cleared). | |
value | string | yes | Current query (controlled). | |
clearLabel | string | "Clear search" | Accessible name of the clear (×) button. | |
disabled | boolean | Disables the field. | ||
icon | content | Leading icon (default: the search icon); null hides it. | ||
onSubmit | () => void | Called when the user presses Enter. | ||
placeholder | string | "Search" | Hint shown while empty. |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
PinInput #
One-time-code input: one cell per digit, paste fills all cells. Forwarded attributes land on the group.
Enter the 6-digit code.
function Example() {
const code = signal("");
return (
<>
<PinInput
aria-label="Verification code"
length={6}
value={code()}
onChange={code.set}
/>
<Text muted>{code().length === 6 ? `Verifying ${code()}…` : "Enter the 6-digit code."}</Text>
</>
);
}Slots: root cell
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
onChange | (value: string) => void | yes | Called with the new code on every edit or paste. | |
value | string | yes | Digits entered so far (controlled). | |
disabled | boolean | Disables every cell. | ||
length | number | 4 | Number of cells. | |
mask | boolean | Mask digits like a password. |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
TagsInput #
Free-form tag entry (Enter / comma / paste lists, case-insensitive dedupe).
function Example() {
const topics = signal(["signals", "ssr"]);
return (
<TagsInput
aria-label="Topics"
placeholder="Add a topic and press Enter"
value={topics()}
onChange={topics.set}
/>
);
}Slots: root input remove tag
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
onChange | (value: string[]) => void | yes | Called with the new tags (added with Enter or comma; removed with ×). | |
value | string[] | yes | Current tags (controlled). | |
disabled | boolean | Disables adding and removing. | ||
placeholder | string | "Add tag" | Input hint. | |
renderTag | (tag: string) => unknown | Render a tag's content (default: the text). |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
InputGroup #
Joins inputs and addons into one control.
<InputGroup>
<InputAddon>https://</InputAddon>
<TextInput aria-label="Subdomain" value="acme" />
<InputAddon>.arachne.app</InputAddon>
</InputGroup>| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | content | Inputs, buttons and InputAddons to join edge to edge. |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
Parts
InputAddon #
Static addon (text, icon) attached to an input.
<InputGroup>
<InputAddon>$</InputAddon>
<TextInput aria-label="Amount" value="49.00" />
</InputGroup>| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | content | Addon text or content, e.g. https:// or a unit. |
InlineEdit #
Click-to-edit text.
function Example() {
const name = signal("Marketing site");
return <InlineEdit label="Project name" value={name()} onChange={name.set} />;
}Slots: root display icon input
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
onChange | (value: string) => void | yes | Called with the new text when an edit is committed (Enter or blur); Escape cancels. | |
value | string | yes | Current text (controlled). | |
label | string | Accessible label for the edit button / input. | ||
placeholder | string | Text shown while the value is empty. |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
JsonInput #
JSON text area that flags invalid JSON (aria-invalid, data-invalid).
function Example() {
const config = signal('{\n "region": "fra1",\n "replicas": 2\n}');
return <JsonInput aria-label="Config JSON" value={config()} onChange={config.set} />;
}| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
onChange | (value: string) => void | yes | Called with the new text on every edit (invalid JSON is flagged, not rejected). | |
value | string | yes | JSON text (controlled). | |
disabled | boolean | Disables the field. | ||
name | string | Field name submitted with the form. | ||
rows | number | 6 | Visible text lines. |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.
Secret & copy fields #
Read-only values to reveal or copy.
SecretField #
Masked secret with reveal / copy.
••••••••••••••••<SecretField label="Webhook secret" value="whsec_9f2kQ83m1x" />Slots: root actions label value
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
value | string | yes | The secret (masked until revealed). | |
label | content | Field label. |
CopyField #
Read-only value with a copy button.
sk_live_51Hx…9fQ2<CopyField label="API key" value="sk_live_51Hx…9fQ2" />Slots: root action label value
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
value | string | yes | Text shown and copied. | |
label | string | Field label (also the copy button's accessible context). |
Also accepts the shared props: pass-through attributes, class, style, classes, styles, unstyled.