Skip to main content

Input

Implemented

Text 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`.

Categoryatoms
Sourcepatterns/atoms/input.html
AI HintLabelled text input with merged error/hint wiring (aria-describedby), leading/trailing icon slots, labelHidden and chromeless modes. Use ariaLabel when the visible label is not the right accessible name; composite search pills compose it chromeless. ADR-070: field rows use the overlay construction (pointer-events-none absolute icon over a full-width padded input) — never compose an icon as an inline sibling of an input; see docs/decisions/ADR-070-search-field-composition.md.

Single-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

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 required is 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 is focus:outline-none and never self-rings.
  • chromeless strips the wrapper ring: the parent that provides the chrome owns the indicator. Pass focusRing="self" only for bare fields with no parent focus chrome.
  • Every ring-offset-2 in the DS carries ring-offset-ep-bg so the offset halo stays theme-safe in dark mode.

Props

Prop
Type
Default
Description
label*
string
—

Visible and announced label.

value*
string
—

Controlled value.

onChange*
(value: string) => void
—

Change handler (string-typed).

type
InputType
text

Native input type.

placeholder
string
—

Placeholder text. Never replaces the visible label.

helperText
string
—

Long-form helper copy.

hint
string
—

Alias for helperText — dashboard form convention.

error
string
—

Validation error announced via aria-describedby.

required
boolean
false

Marks the field required.

leadingIcon
React.ReactNode
—

Decorative leading icon.

trailingIcon
React.ReactNode
—

Decorative trailing icon.

ariaLabel
string
—

Override the announced label.

chromeless
boolean
false

Strip 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

Preview

Input

Prop
Type
Required
Default
Description
label
string
Required
—
No description.
value
string
Required
—
No description.
onChange
(value: string) => void
Required
—
No description.
error
string
Optional
—

Sets aria-invalid + aria-describedby to error message

required
boolean
Optional
False
No description.
type
InputType
Optional
'text'

Underlying element/input type.

placeholder
string
Optional
—

Placeholder text shown when the value is empty.

helperText
string
Optional
—

Helper text rendered below the control.

hint
string
Optional
—

Alias for `helperText`.

leadingIcon
React.ReactNode
Optional
—

Synced from source — no interface JSDoc yet; document on `Input.tsx`.

trailingIcon
React.ReactNode
Optional
—

Synced from source — no interface JSDoc yet; document on `Input.tsx`.

ariaLabel
string
Optional
—

Synced from source — no interface JSDoc yet; document on `Input.tsx`.

labelHidden
boolean
Optional
false

Synced from source — no interface JSDoc yet; document on `Input.tsx`.

chromeless
boolean
Optional
false

Synced from source — no interface JSDoc yet; document on `Input.tsx`.

Quick use:<Input />

Accessibility

ARIA roletextbox

Type

1 rule

NASA Rule 5

label must be non-empty string

ARIA

1 rule

WCAG 1.3.1, 3.3.1

error must set aria-invalid='true' and aria-describedby to the error message id

Usage

Import

tsxSnippet
import { Input } from "@epasslive/design-system"

Example 1

tsxSnippet
<Input label="Email" type="email" />

Example 2

tsxSnippet
<Input label="Password" type="password" required />

Anti-patterns

— Do not compose atoms directly — use molecules instead

— Avoid inline styles on atoms

Design System v4.1.0 | ePassLive