Back to reviews and guides

WCAG 4.1.2 Name, Role, Value: Making Custom Interface Components Accessible

WCAG 4.1.2 requires interactive UI components to expose a programmatic name, role and state or value so assistive tech can use them. This guide gives concrete steps, common fixes, a decision framework for native vs ARIA, and a testing checklist.

What WCAG 4.1.2 requires

WCAG 4.1.2, Name, Role, Value, requires that user interface components expose a programmatically determined name, a role, and any current state or value. This means assistive technologies must be able to discover what a control is, what it is called, and what its current state or value is. The criterion is Level A and applies whenever content exposes a custom control, widget or state that people must operate or perceive.

When this applies

Apply the rule to any interactive UI element that is not purely presentational. That includes custom buttons, toggles, sliders, tabs, grids, tree views, combo boxes and form controls built from generic elements. It also applies to states and properties that change in response to user action, for example selection, expansion, checked state and numeric values.

How to meet 4.1.2 — practical steps

Follow this order when you build or audit a component. Start with native HTML. Add ARIA only to fill gaps.

1. Use native elements where possible

  • Prefer button, input, select, textarea and native range controls. Native controls already expose name, role and value.
  • Native controls also handle keyboard and focus automatically.

2. Give every interactive control an accessible name

  • Visible labels are best. Use an HTML <label> or visible text that clearly identifies the control.
  • If there is no visible label, provide a programmatic name with aria-label or reference visible text with aria-labelledby.
  • Avoid using placeholder text as the only label. Placeholders are not a reliable programmatic name.

3. Set the correct role

  • Do not guess. Use semantic HTML first. If you must use ARIA, set a role such as role=“button”, role=“checkbox” or role=“slider” that matches the control’s behaviour and keyboard model.
  • Roles must match behaviours. A role that says “button” must respond to Enter and Space like a button.

4. Expose state and value attributes

  • For on/off controls use aria-checked or native checked state.
  • For expandable regions use aria-expanded.
  • For ranges use aria-valuenow, aria-valuemin and aria-valuemax, or use the native input type=“range”.
  • Keep these attributes in sync with the visual state whenever the state changes.

Common mistakes and how to fix them

  • Relying only on visible text that is not linked programmatically. Fix: use aria-labelledby or a label element that references the control.
  • Using placeholder as the only label. Fix: add a proper label element or aria-label.
  • Changing visual state but not updating ARIA attributes. Fix: update the relevant aria-* attribute when state changes.
  • Using role without matching keyboard support. Fix: implement the role’s keyboard interactions or use a native element.
  • Hiding the label with aria-hidden then not providing another name. Fix: do not hide the accessible name source.

Decision framework: native element or ARIA?

Use native HTML Use ARIA Risk if you choose ARIA
When element behavior matches a standard control (buttons, inputs, selects, range). When a custom visual or behaviour cannot be achieved with native controls. Extra code to maintain name, role and value. More testing needed with assistive tech.

Two practical patterns developers miss

Pattern 1 — label separation

If the visible label is outside the DOM node that holds the control, reference it with aria-labelledby. That makes the visual label the programmatic name and avoids duplicate names.

Pattern 2 — dynamic state updates

When a widget changes state after user action, update the corresponding aria-* attribute the same time you update the UI. For example, when a custom toggle switches, set aria-checked immediately, not only on page reload.

Testing and debugging checklist

  1. Open the browser accessibility tree or accessibility inspector and find the element. Confirm it has a name, a role, and a value if applicable.
  2. Test with at least one screen reader such as NVDA or VoiceOver. Navigate to the component and verify the screen reader announces the name, role and state.
  3. Use only the keyboard. Verify focus, activation keys and that state updates are announced.
  4. Simulate no-visual cues. Turn off CSS or inspect with high contrast to ensure the programmatic name remains available.
  5. Review ARIA attributes for accuracy and consistency. Remove redundant or incorrect ARIA that conflicts with native semantics.

Audit checklist you can copy

  • Does every interactive element have an accessible name? (label element, aria-label, aria-labelledby)
  • Does every interactive element have an appropriate role? Prefer native semantics.
  • Are states exposed and kept in sync? (aria-checked, aria-expanded, aria-valuenow)
  • Are values exposed for range or composite widgets? Is the value programmatically writable or reported?
  • Does keyboard operation match the announced role?
  • Do screen readers announce changes to state when they occur?

Short examples explained

Example: a custom icon button with no visible text. If the visual label is an icon, add aria-label=“Close” or create a visible label and reference it with aria-labelledby. If you use a div with role=“button”, also add tabindex=“0” and keyboard handlers for Enter and Space.

Example: a custom slider built from divs. Use role=“slider”, and set aria-valuemin, aria-valuemax and aria-valuenow. Update these attributes whenever the value changes so assistive tech receives the current value.

Final practical tips

  • Document the accessible name source for each component. Prefer visible labels and reference them programmatically.
  • Automated tools can catch missing names and roles, but manual screen reader checks are essential for state and value announcements.
  • Keep ARIA minimal and accurate. If native HTML does the job, use it. If you add ARIA, treat the accessibility tree as the source of truth and test regularly.