Input

How the Input works with a keyboard and assistive tech, and where it stands against WCAG 2.2 AA.

FreeReact and VueInput blocks24 blocksPro
AAWCAG 2.2 target
12/20contrast pairs passing
5keyboard interactions

The Input is a native <input> with a <label> tied to it by for and id, and a hint linked with aria-describedby. The browser supplies typing, selection and the right keyboard for the type. What is left is the name, the error state, and contrast for a field drawn with a pale stroke.

Keyboard#

Tab

Moves focus into the field, then to its show-password, copy or Verify button where there is one.

Shift+Tab

Moves focus to the previous focusable element.

Enter

Submits the form the field is in. In a search field, runs the search.

Escape

In a search field, clears the text, as the browser does.

Space

On the show-password button, shows or hides the password.

Semantics#

<label for>

Gives the field its name, and a click on the label focuses the field.

Always
type="search" | "password" | "url"

Matches the content, so devices show the right keyboard and password managers recognise the field.

Per type
required

Announced as required. The red asterisk is hidden from assistive tech because this says it.

required
aria-invalid="true"

Announced as invalid. The hint says what to fix.

error
aria-describedby

Links the hint or error, so it is read after the name.

Hint
autocomplete

Password fields use current-password. Other types are off by default; pass a token such as email or name for anything about the person.

Personal data
aria-label="Show password"

The button's name says what it will do, and changes to Hide password.

Password
readonly / disabled

Read Only stays focusable and its value can be copied; Disabled leaves the tab order.

Read Only, Disabled

Colour contrast#

Every variant and state has to meet WCAG 2.2 Level AA. Measure the colours as they land on screen: a translucent hover or press wash over whatever sits behind it.

4.5:1

Value and label · Default, Hover, Focused, Read Only

The value and label in #2a2a2a, on white, the 4% hover wash and the #f2f2f2 read-only fill. All pass.

WCAG 1.4.3 Contrast (Minimum) ↗
4.5:1

Placeholder · Empty

#8f8f8f measures 3.23:1 on white and less on hover. Placeholder text is text, so it fails, and it is no substitute for a label.

WCAG 1.4.3 Contrast (Minimum) ↗WCAG 3.3.2 Labels or Instructions ↗
3:1

Field boundary · Default, Hover

The 1px #e1e1e1 stroke is 1.31:1 on white: the field is hard to find on a white page. The focused (#070707) and error (#ec0d33) strokes pass.

WCAG 1.4.11 Non-text Contrast ↗
Not colour alone

Error · Error

The red stroke is backed by the hint's words and aria-invalid. The hint's red is 4.49:1, a hair under 4.5:1.

WCAG 1.4.1 Use of Color ↗WCAG 3.3.1 Error Identification ↗
3:1

Focus indicator · Focus visible

A 2px ring in #1a6ef8 off a white gap, on keyboard focus only. It measures 4.54:1 on white, so it clears 3:1 on every light surface the library uses.

WCAG 1.4.11 Non-text Contrast ↗WCAG 2.4.13 Focus Appearance ↗
Not required

Disabled · Disabled

Inactive controls are exempt. The disabled text and glyphs (#cbcbcb) are deliberately faint.

WCAG 1.4.3 Contrast (Minimum) ↗

Measured contrast#

Each part against the field's white fill, or the 4% hover wash over it, from the ds.css tokens; text is held to 4.5:1 and the stroke and glyph, as graphics, to 3:1. 8 of 20 pairs fall below their minimum (4.5:1 for text, 3:1 for graphics) and are marked in amber.

Part · elementDefaultHoverFocusedError
Field · value14.35passes13.17passes14.35passes14.35passes
Field · placeholder3.23below the minimum2.97below the minimum3.23below the minimum3.23below the minimum
Field · stroke1.31below the minimum1.20below the minimum20.14passes4.49passes
Field · leading glyph3.23passes2.97below the minimum3.23passes3.23passes
Hint · text5.17passes5.17passes5.17passes4.49below the minimum

Motion#

  • The fill and stroke change over 150ms, and are turned off under prefers-reduced-motion.

Checklist#

Every field has a visible label. A placeholder is not a label: it disappears as soon as someone types.

Pass an autocomplete token for anything about the person (name, email, tel, street-address); the component's default is off (WCAG 1.3.5).

The placeholder (#8f8f8f, 3.23:1) is under 4.5:1. Use it only for an example that is also safe to miss, never for instructions.

The resting stroke (#e1e1e1, 1.31:1) is under the 3:1 non-text minimum, so an empty field on white is hard to see. It needs a darker stroke before the code library ships.

The show-password button sets aria-pressed as well as changing its name, so it is announced as Hide password, pressed. Keep one: the changing name.

Validate on blur or submit, not on every keystroke, and move focus to the first invalid field on submit.

The field is 60px tall and the whole box focuses the input, well over the 24px minimum.