Input
Single-line text field that adopts every native HTML `type` and exposes token-driven focus, error, and disabled states.
Overview
Input is a thin styled wrapper around the native <input> element. Pass any HTML type (text, email, password, number, search, tel, url, file, date...) and the browser semantics, validation, and virtual keyboard all come along for free.
All visual states are token-driven: border-input for default, focus-visible:ring-ring/50 for keyboard focus, and aria-invalid:border-destructive for error. There are no variants - inputs should look the same everywhere so users can predict their behavior.
Preview
Installation
bash npx gremorie@latest add rx-input bash pnpm dlx gremorie@latest add rx-input bash yarn dlx gremorie@latest add rx-input bash bunx --bun gremorie@latest add rx-input Usage
import { Input, Label } from "@gremorie/rx-forms";
export function Example() {
return (
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="you@example.com" />
</div>
);
}Angular edition planned for Phase 5h. Star the repo to track progress.
API
<Input>
| Prop | Type | Default | Description |
|---|---|---|---|
type | string | "text" | Any native HTML input type. Drives keyboard, validation, and platform UI (e.g. date picker, file dialog). |
disabled | boolean | false | Disables interaction. Applies pointer-events-none and opacity-50. |
aria-invalid | boolean | - | When true, switches border and focus ring to the destructive token. |
Extends all React.ComponentProps<"input">. Renders with data-slot="input" so the parent InputGroup can drive group-wide focus and error states.
Composition
<Input>is a leaf primitive. Pair it with a<Label>(linked viahtmlFor/id) so clicks and screen reader interactions focus the field.- For prefix/suffix icons or buttons, wrap it with
<InputGroup>and use<InputGroupInput>instead of<Input>so the group can drive shared focus states. - For form-bound usage, wrap it in a
<FormField>+<FormControl>so labels, descriptions, and error messages auto-wire ARIA relationships.
Variations
Email field with placeholder
The canonical pattern. type="email" triggers the email keyboard on mobile and enables built-in browser validation.
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="you@example.com" />
</div>Number input with min/max
type="number" shows numeric keyboard on mobile and accepts min, max, step for browser validation.
<div className="grid gap-2">
<Label htmlFor="quantity">Quantity</Label>
<Input id="quantity" type="number" min={1} max={99} defaultValue={1} />
</div>Error state
Drive aria-invalid from your validation library. The destructive ring and border come for free.
<div className="grid gap-2">
<Label htmlFor="email-bad">Email</Label>
<Input
id="email-bad"
type="email"
aria-invalid
aria-describedby="email-error"
defaultValue="not-an-email"
/>
<p id="email-error" className="text-sm text-destructive">
Please enter a valid email.
</p>
</div>File input
type="file" renders the native picker. The internal file: selectors style the button-like trigger.
<div className="grid gap-2">
<Label htmlFor="avatar">Avatar</Label>
<Input id="avatar" type="file" accept="image/*" />
</div>Accessibility
- Labels: every input needs an associated
<Label>(viahtmlFormatching the inputid) or an explicitaria-label. - Focus: 3px focus-visible ring driven by
focus-visible:ring-ring/50, so it only appears for keyboard users. - Validation: combine
aria-invalid="true"witharia-describedbypointing at the error message so screen readers announce the failure when focus enters the field. - Disabled:
disabledremoves the input from the tab order and prevents activation, including from JavaScript-issued focus. - Autocomplete: respect platform conventions by setting
autoComplete="email","current-password","one-time-code", etc.
Related
- Label - the accessible label primitive
- Input Group - wrap Input with icons, buttons, or kbd hints
- Textarea - multi-line counterpart
- Form - wires Input to react-hook-form with ARIA helpers
- Input OTP - segmented input for one-time codes