Input
ImplementedText input with label, helper, error, and disabled states. Focus indication is painted by the wrapper via `focus-within:ring-2 ring-ep-teal border-ep-teal`; the inner `<input>` carries `focus:outline-none` so the browser's default outline does not stack. Required for all forms. ADR-071: exactly one focus indicator per field group, owned by the chrome container — chromeless mode never self-rings by default; `focusRing="self"` is the opt-in for bare fields with no parent focus chrome. Every `ring-offset-2` carries `ring-offset-ep-bg`.
patterns/atoms/input.htmlSingle-line text input with label, helper text, error state, and leading/trailing icon slots. FR-CA: Champ de saisie monoligne.
Input
Interactive atom (Family 1 — Tier 1)
Always renders a visible label and binds aria-describedby to the helper / error message.
8 caractères minimum
Doit être entre 1 et 10
This component supports light and dark mode.
Interactive demo
Au moins 8 caractères
Usage
import { Input } from '@epasslive/design-system'
<Input label="Courriel" type="email" value={email} onChange={setEmail} required hint="Nous ne partagerons jamais votre adresse." />Accessibility
- Label associated with the input via a generated id + htmlFor.
- Helper text + error both bind via aria-describedby.
- When
requiredis true,aria-required="true"is set and the label gains an asterisk.
Focus contract (ADR-071)
- Exactly one focus indicator per field group, painted by the outermost chrome container via
focus-within— never a stacked double box. - Default mode: the bordered wrapper rings on
focus-within; the input isfocus:outline-noneand never self-rings. chromelessstrips the wrapper ring: the parent that provides the chrome owns the indicator. PassfocusRing="self"only for bare fields with no parent focus chrome.- Every
ring-offset-2in the DS carriesring-offset-ep-bgso the offset halo stays theme-safe in dark mode.
Props
label*stringVisible and announced label.
value*stringControlled value.
onChange*(value: string) => voidChange handler (string-typed).
typeInputTypetextNative input type.
placeholderstringPlaceholder text. Never replaces the visible label.
helperTextstringLong-form helper copy.
hintstringAlias for helperText — dashboard form convention.
errorstringValidation error announced via aria-describedby.
requiredbooleanfalseMarks the field required.
leadingIconReact.ReactNodeDecorative leading icon.
trailingIconReact.ReactNodeDecorative trailing icon.
ariaLabelstringOverride the announced label.
chromelessbooleanfalseStrip the wrapper chrome (border, surface, focus-within ring, padding) — the parent provides it.
focusRing"parent" | "self""parent"ADR-071: who owns the focus indicator. "self" renders the input-owned focus-visible ring for bare chromeless fields.
Props
Input
labelstring—valuestring—onChange(value: string) => void—errorstring—Sets aria-invalid + aria-describedby to error message
requiredbooleanFalsetypeInputType'text'Underlying element/input type.
placeholderstring—Placeholder text shown when the value is empty.
helperTextstring—Helper text rendered below the control.
hintstring—Alias for `helperText`.
leadingIconReact.ReactNode—Synced from source — no interface JSDoc yet; document on `Input.tsx`.
trailingIconReact.ReactNode—Synced from source — no interface JSDoc yet; document on `Input.tsx`.
ariaLabelstring—Synced from source — no interface JSDoc yet; document on `Input.tsx`.
labelHiddenbooleanfalseSynced from source — no interface JSDoc yet; document on `Input.tsx`.
chromelessbooleanfalseSynced from source — no interface JSDoc yet; document on `Input.tsx`.
<Input />Accessibility
Type
1 ruleARIA
1 ruleUsage
Import
import { Input } from "@epasslive/design-system"Example 1
<Input label="Email" type="email" />Example 2
<Input label="Password" type="password" required />Anti-patterns
— Do not compose atoms directly — use molecules instead
— Avoid inline styles on atoms