Skip to main content
Gremorie

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>

PropTypeDefaultDescription
typestring"text"Any native HTML input type. Drives keyboard, validation, and platform UI (e.g. date picker, file dialog).
disabledbooleanfalseDisables interaction. Applies pointer-events-none and opacity-50.
aria-invalidboolean-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

  1. <Input> is a leaf primitive. Pair it with a <Label> (linked via htmlFor / id) so clicks and screen reader interactions focus the field.
  2. For prefix/suffix icons or buttons, wrap it with <InputGroup> and use <InputGroupInput> instead of <Input> so the group can drive shared focus states.
  3. 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> (via htmlFor matching the input id) or an explicit aria-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" with aria-describedby pointing at the error message so screen readers announce the failure when focus enters the field.
  • Disabled: disabled removes 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.
  • 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

On this page