MiHCM
primitives/@mihcm/ui·v0.21.0·stable

Input

Single-line text entry. Default + destructive variants, three sizes, optional leading/trailing icons. WCAG 2.1 AA out of the box (aria-invalid, aria-required, focus ring).

WCAG 2.1 AA — release blocker

Input must satisfy these on every render before it ships.

Web (React DOM)

  • The wrapper carries the focus indicator via focus-within:ring-2, so the visible focus state wraps the input and the leading/trailing icons. Never outline: none without a replacement.
  • aria-invalid is set when invalid={true} (or when aria-invalid is passed through explicitly).
  • aria-required is set when required={true}.
  • aria-describedby is not rendered by the component — pair the input with an error message element and link them yourself. The wiring is intentional: where the message lives in the layout is a consumer concern, not the primitive's.
  • Color contrast on the placeholder, the border, and the destructive variant has been verified ≥ 4.5:1 against the wrapper background.

React Native

  • Wrapper is a <View>; the input is <TextInput>. accessibilityLabel is forwarded to the <TextInput>.
  • accessibilityState.disabled mirrors editable={false}.
  • For invalid state, the destructive border carries the visual signal. Pair with accessibilityHint so screen readers announce the error after the label.

Label association

Input does not render its label. Use a <label htmlFor> (web) or rely on accessibilityLabel (native). The reason: every form layout positions labels differently — above, beside, inside the field with a float — and burying the label inside the primitive forces all of them into one position.

Reduced motion

Only the border-color transition runs (200 ms). The user agent honours prefers-reduced-motion automatically; no special handling needed.

Audit checklist

  • Wrapper shows a visible focus ring on tab-in (light and dark).
  • invalid={true} sets aria-invalid and applies the destructive style in one step.
  • required={true} sets aria-required.
  • Error message is referenced from aria-describedby and is announced by screen readers after the label.
  • Placeholder is never the only label — every input has an associated <label> or accessibilityLabel.
  • Touch target ≥ 44 px on size="lg".
  • Color contrast ≥ 4.5:1 on placeholder, border, and destructive variant in both themes.