Lumen Docs

Input

Text input primitive. Located at apps/web/components/ui/input.tsx.

Usage

<Input
  label="Email address"
  placeholder="you@example.com"
  type="email"
  value={email}
  onChange={(e) => setEmail(e.target.value)}
  error={validationError}
  helperText="We'll never share your email."
/>

Props

  • label — optional, renders above the input
  • helperText — optional, below the input in muted text
  • error — optional, renders in error color below (replaces helperText)
  • All native <input> props pass through

Variants

Default

<Input label="Project name" />

With validation error

<Input
  label="Email"
  value={email}
  onChange={(e) => setEmail(e.target.value)}
  error={email && !email.includes("@") ? "Invalid email" : undefined}
/>

Border turns error-colored, helper text replaced with error text.

Password

<Input
  type="password"
  label="Password"
  placeholder="Minimum 8 characters"
/>

Nothing special — just relies on the native password input. No "show password" toggle in the current impl.

Layout

Height: h-10 default (40px). Radius: --radius-sm (6px). Border: border-line. On focus: border-accent ring-1 ring-accent/20.

Always pair with a <label> either via the label prop or manually. Never rely on placeholder as label.

Don't

  • Don't use <input> native — use <Input> for consistency
  • Don't wrap in <div> if you need vertical spacing — the parent's flex flex-col gap-4 handles it
  • Don't put inline styles for border color — the primitive handles focus/hover/error states