EDS 0.x
Components

Input

Examples

Default

Validation

Affixes & icons

prefix / suffix are outer affix segments. iconStart / iconEnd sit inside the field and follow reading direction in RTL.

$kghttps://.com

Sizes

TanStack Form

Submit with an empty or invalid email to see field validation. A valid email clears the error and shows a success message.

RTL

Wrap the field (or a parent) in dir="rtl" / lang="fa". Outer prefix / suffix and iconStart / iconEnd follow the reading direction.

تومانکیلوگرم

API Reference

PropTypeDefaultDescription
size"sm" | "md""md"Field height
validation"none" | "error" | "success""none"Invalid (negative) / Valid (positive)
prefixReactNodeOuter inline-start affix
suffixReactNodeOuter inline-end affix
iconStartReactNodeIcon inside the field at inline-start
iconEndReactNodeIcon inside the field at inline-end
classNamestringClass on the outer chrome
inputClassNamestringClass on the native <input>
disabledbooleanDisabled state
readOnlybooleanRead-only state
native input attrsvalue, onChange, onBlur, name, placeholder, etc.

Accessibility

WCAG success criteria

CriterionLevelHow EDS helps
1.3.1 Info and RelationshipsANative input preserves semantic relationships; consumer wires labels and aria-describedby for errors
3.3.1 Error IdentificationAvalidation="error" sets invalid visuals + aria-invalid="true"; consumer must expose error text (e.g. role="alert")
3.3.2 Labels or InstructionsASupports placeholder, native required, and all standard labeling attrs on the <input>
3.3.3 Error SuggestionAAConsumer: provide actionable error copy linked via aria-describedby
2.4.7 Focus VisibleAAToken-based focus ring on :focus-within
1.4.3 Contrast (Minimum)AAInput text and borders use EDS color tokens
1.4.11 Non-text ContrastAABorder, focus ring, and validation indicators target 3:1 against adjacent colors
4.1.2 Name, Role, ValueANative <input> exposes name (via label/aria), role, value, and states (disabled, readonly, invalid)
2.1.1 KeyboardAFully operable via keyboard through the native control

Why it matters

Text inputs are the primary way users enter personal, financial, and operational data. If a field lacks a visible label, error association, or keyboard focus indicator, people who use screen readers, keyboards, or magnifiers cannot complete tasks — and everyone suffers when validation feedback is unclear. EDS keeps the native <input> as the focus target so form libraries, browser autofill, and assistive tech work without adapters.

Getting labeling or error wiring wrong is a compliance and product risk: users abandon forms, support tickets spike, and WCAG audits fail on basic field patterns.

Keyboard

The native <input> receives focus and handles all standard text-field keys. Chrome wrappers (prefix, icons, focus ring) are not in the tab order.

Key / actionBehavior
⇥ TabMoves focus to the <input> (skips decorative chrome)
+ ⇥ TabMoves focus to the previous focusable element
Type / / DeleteStandard text entry and editing
/ Home / EndMove caret within the value
↵ EnterSubmits the nearest <form> unless prevented
⎋ EscBrowser-default (e.g. clears autocomplete in some contexts) — no EDS override
StateKeyboard behavior
DefaultFully interactive
disabledRemoved from tab order; not editable
readOnlyFocusable and selectable; value cannot be changed
validation="error"Still fully editable — errors do not block typing
validation="success"Same as default; success icon is decorative

Screen readers & semantics

ElementSemantics
<input> (ref target)Native text field — exposes role, value, states to AT
iconStart / iconEnd / success iconWrapped in aria-hidden="true" — decorative; do not convey meaning alone
prefix / suffix affixesVisual chrome only; not automatically linked to the input name
Focus ring (eds-input__focus-ring)aria-hidden="true" — visual only; focus is on the input
ConcernEDS / consumer responsibility
Accessible nameConsumer: associate <label htmlFor={id}>, or pass aria-label / aria-labelledby
Invalid stateEDS sets aria-invalid="true" when validation="error" (overridable via aria-invalid prop)
Error descriptionConsumer: link error text with aria-describedby={errorId} pointing to the error element
requiredConsumer: pass native required; consider aria-required if not using native constraint validation
disabled / readOnlyNative attributes forwarded — AT announces state correctly

forwardRef targets the <input> so programmatic focus (ref.current.focus()) and scroll-into-view from form libraries work as expected.

Focus & visuals

ConcernEDS behavior
Focus visible:focus-within on the chrome shows a token-based focus ring (--eds-input-focus-ring) around the field and affixes
HoverBorder emphasis on hover when not disabled, read-only, or focused
Validation colorsvalidation="error" applies negative border tokens; validation="success" applies positive border + optional check icon
DisabledMuted visuals; no hover or focus ring treatment
RTLprefix / suffix and iconStart / iconEnd use logical inline-start/end — layout mirrors under dir="rtl"
ContrastText and borders use EDS semantic tokens intended to meet WCAG AA on default surfaces

The success checkmark is visual confirmation only — do not rely on it as the sole indicator of validity for screen-reader users; pair with text or programmatic state.

Build with it

DoDon’t
Pair every field with a visible <label htmlFor={id}> or aria-labelRely on placeholder as the only label
Wire aria-describedby to error/helper text elementsShow red borders with no text explanation
Set validation="error" and aria-invalid together in form bindingsToggle only the border color without aria-invalid
Mark decorative icons with aria-hidden (EDS does this for built-in icons)Pass meaningful icons without a text alternative
Use prefix/suffix for visual units ($, kg) when the label already explains the fieldLet affixes replace proper labeling
Forward name, onChange, onBlur for TanStack Form / native formsWrap the input in a custom component that breaks ref forwarding
Use disabled for non-applicable fields; readOnly for display-with-copyUse disabled for “locked after submit” if the value must still be submitted

Validated field pattern:

const errorId = "email-error";

<>
  <label htmlFor="email">Email</label>
  <Input
    id="email"
    name="email"
    validation={invalid ? "error" : "none"}
    aria-invalid={invalid}
    aria-describedby={invalid ? errorId : undefined}
  />
  {invalid ? (
    <p id={errorId} role="alert">
      Enter a valid email address
    </p>
  ) : null}
</>;

See Usage → TanStack Form for a complete useForm binding example.

Quick test

  1. Keyboard-only — Tab to the input, type text, Shift+Tab away. Confirm a visible focus ring appears and the caret is in the field.
  2. Label — With VoiceOver/NVDA, focus the field. Confirm the accessible name matches the visible label (not just placeholder).
  3. Error state — Set validation="error" with linked error text via aria-describedby. Confirm AT reads the field as invalid and announces the error.
  4. Disabled / read-only — Tab to each. Disabled should be skipped; read-only should focus but not accept edits.
  5. Icons & affixes — Add iconStart and prefix. Confirm AT does not double-announce icon/affix content.
  6. RTL — Wrap in dir="rtl" lang="fa". Confirm affixes and icons flip to inline-start/end correctly.
  7. Zoom — At 200% browser zoom, confirm the field, label, and error text remain visible without horizontal clipping.

On this page