Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

TextField

A labelled box for a line of text, with a hint, an error and optional icons.

import { TextField } from "@butteryui/react";

Demo

Shown on your receipts.

When to use it

Use it for

  • A name, an email address, a search, a title: any single line of text
  • Sign-in and sign-up forms, at size lg
  • A field on a card or in a toolbar, with variant="soft"; a dense panel or a toolbar, with size="sm"

Not for

  • A password: use PasswordField
  • Text that can run to several lines: use TextArea
  • An exact number with steps: use NumberField

Examples

Email field

An email address checked when you leave the field, with the browser's autofill.

Gift card title

A gift card's title with a hint, uncontrolled: the form reads it when it's sent.

Shown large on the gift card

The card says Happy birthday

Shipping address

A shipping address form: a field for each line, two side by side where they're short, checked on Save.

Shop name

A shop's name kept in state, which also writes the web address the shop will get.

Name your shop to get its address

Sizes

The sizes and looks: a small soft field for a toolbar, md for forms in an app, lg with 16px text for a sign-in page.

Variants and states

States

Empty, filled with a hint, with an error, and disabled.

Shown large on the gift card

Email: Enter an email address like name@example.com.

Enter an email address like name@example.com.

Sizes and icons

28px for a toolbar or a dense panel; 34px for app forms; 48px with 16px text for sign-in pages.

Outline and soft

Outline, the default, has a 1px edge; soft sits on bg-control and shows its edge only on hover and while it has focus. An error's edge shows in both.

Tasting notes: Write at least three notes.

Write at least three notes.

Props

TextField

PropTypeDefaultDescription
label

required

stringWhat the field asks for, shown above it.
hintReactNodeA hint under the label, such as the format expected.
errorReactNodeWhat's wrong, shown under the field and read with it. Leave it out while nothing is.
valuestringThe text. Pair with onValueChange or onChange to control it.
defaultValuestringThe starting text when uncontrolled.
onValueChange((value: string) => void)Called with the text on every change.
sizeTextFieldSize"md""md" (34px, 30 compact, the default), "sm" (28px) for a toolbar or a dense panel, or "lg" (48px, 40 compact, with 16px text) for sign-in pages.
variant"outline" | "soft""outline""outline" (the default), a 1px control-border edge on bg-surface, or "soft", a bg-control fill whose edge shows only on hover and while it has focus, for a field on a card or in a toolbar.
iconStartComponentType<IconComponentProps>An icon at the start of the box, such as Mail from lucide-react. Decorative.
iconEndComponentType<IconComponentProps>An icon at the end of the box. Decorative.
announceErrorbooleantrueWhether a new error is read out as it appears. Defaults to true; turn it off when an error summary that takes focus reads the errors instead.

It also takes Omit<ComponentPropsWithRef<"input">, "size" | "value" | "defaultValue" | "children">.

TextField.Shell

PropTypeDefaultDescription
root

required

{ readonly className: string | undefined; readonly "data-bt": string; }The root's class and data-bt, so each field keeps its own name.
endReactNodeSomething after the input inside the box, such as a reveal button.
afterReactNodeContent under the error, such as a password's requirements.
afterIdstringThe id of after, read after the hint and the error when the input is described.
label

required

stringWhat the field asks for, shown above it.
hintReactNodeA hint under the label, such as the format expected.
errorReactNodeWhat's wrong, shown under the field and read with it. Leave it out while nothing is.
valuestringThe text. Pair with onValueChange or onChange to control it.
defaultValuestringThe starting text when uncontrolled.
onValueChange((value: string) => void)Called with the text on every change.
sizeTextFieldSize"md""md" (34px, 30 compact, the default), "sm" (28px) for a toolbar or a dense panel, or "lg" (48px, 40 compact, with 16px text) for sign-in pages.
variant"outline" | "soft""outline""outline" (the default), a 1px control-border edge on bg-surface, or "soft", a bg-control fill whose edge shows only on hover and while it has focus, for a field on a card or in a toolbar.
iconStartComponentType<IconComponentProps>An icon at the start of the box, such as Mail from lucide-react. Decorative.
iconEndComponentType<IconComponentProps>An icon at the end of the box. Decorative.
announceErrorbooleantrueWhether a new error is read out as it appears. Defaults to true; turn it off when an error summary that takes focus reads the errors instead.

It also takes Omit<ComponentPropsWithRef<"input">, "size" | "value" | "defaultValue" | "children">.

Accessibility

The visible label names the input and the hint and error describe it, with aria-invalid while there's an error; a new error is read out with the field's name as it appears (announceError={false} where an error summary reads it). The box has a 3:1 edge. Pass type, autoComplete and inputMode so browsers and password managers can fill it in and phones show the right keyboard. The whole box takes a press, and the focus ring shows on it.

KeysWhat they do
Letters, numbers and symbolsTypes them in
EnterSubmits the form it's in, as any text input does

Motion

It doesn't move.

With reduced motion: Nothing changes.

Layout

It fills its container's width. The box is --bt-h-control (34px, 30 compact) tall, --bt-h-sm (28px) at size="sm", or --bt-h-cta (48px, 40 compact) with 16px text at size="lg", and the whole box is the hit area, its icons included; an outline box draws a 1px edge, and a soft one keeps that edge transparent until hover or focus, so the box never moves; text longer than the box scrolls inside the input. The label, the hint and the error sit above and below the box and wrap.

See it in the roastery demo's settings. See it in the Halfmoon shop demo. See it in the Deckhand demo.