slop audit
Blog post 25 / Accessibility and semantics

Accessible name: HTML and ARIA testing guide

Use this accessible name guide to label buttons, links, and form controls, avoid ARIA conflicts, test production HTML, and catch failures before launch.

By Slop Audit · 9 min read

An accessible name is the text that identifies a button, link, input, or other interface element to assistive technology. A control can look obvious on screen and still have no useful name in the accessibility tree. That leaves screen-reader and voice-control users guessing what the control does.

Use this guide to choose the right HTML, catch name conflicts, and test the deployed page before launch. The goal is not to add ARIA everywhere. It is to make each important control understandable through native HTML and visible text whenever possible.

Accessible name checklist

Check the main user path in this order:

  1. List the buttons, links, and fields required to complete the task.
  2. Confirm that every control has a specific name outside its visual context.
  3. Prefer visible text and native HTML over an ARIA override.
  4. Associate every form field with a real label.
  5. Keep the visible label inside the programmatic name.
  6. Inspect the rendered accessibility tree, not only the source.
  7. Test important names with role-based browser assertions.
  8. Repeat the check on the deployed public URL.

The MDN accessible name definition explains that a name may come from visible or invisible content depending on the element and its markup. That flexibility is useful, but it also means a late aria-label can replace a good name that already came from visible text.

Understand what creates an accessible name

The browser computes a control's accessible name from sources such as text content, an associated label, aria-labelledby, or aria-label. The exact order depends on the element and the accessibility specifications. Do not concatenate attributes in a test and assume that you reproduced the browser's result.

W3C guidance on names and descriptions recommends visible text labels because they help more people and provide a reliable name source. Start with markup like this:

<a href="/pricing">View pricing</a>
<button type="button">Save draft</button>

<label for="project-url">Public project URL</label>
<input id="project-url" name="project-url" type="url">

Each control exposes a useful name without extra ARIA. The text also tells sighted users what will happen.

Avoid names that only make sense beside an icon or heading:

<!-- Too vague when read as a list of controls. -->
<button type="button">Go</button>
<a href="/docs/setup">Learn more</a>

Replace them with names tied to the result, such as Run audit and Read the setup guide. Review the website content audit checklist when the problem is unclear action copy rather than missing markup.

Prefer visible text and native HTML

Native elements provide a role, keyboard behavior, and a predictable way to calculate the name. A styled button is safer than a clickable div that needs a role, focus handling, and keyboard event code.

<!-- Prefer this. -->
<button type="button">Open filters</button>

<!-- This needs extra behavior and is easy to get wrong. -->
<div role="button" tabindex="0">Open filters</div>

WCAG 2.2 Name, Role, Value requires user-interface names and roles to be programmatically determinable. The W3C notes that standard HTML controls satisfy much of that contract when they are used according to their specification. Custom widgets need more explicit work for their role, name, state, value, and keyboard behavior.

Do not add aria-label to a text button as routine cleanup. It can override the text that the browser would otherwise use. If the visible button says Save draft but the ARIA name says Submit, people using speech input may say the label they see and fail to activate the control.

Label form controls explicitly

Give form fields visible labels and connect them with matching for and id values:

<label for="email">Work email</label>
<input id="email" name="email" type="email" autocomplete="email">

The W3C form-label tutorial recommends explicit labels in most cases. The association lets assistive technology present the right label and gives pointer users a larger activation area.

A placeholder is an example value or hint, not a durable replacement for the label:

<label for="site-url">Website URL</label>
<input
  id="site-url"
  name="site-url"
  type="url"
  placeholder="https://example.com"
  aria-describedby="site-url-help"
>
<p id="site-url-help">Enter a public HTTP or HTTPS page.</p>

Use aria-describedby for supporting instructions or errors. Keep the short identity in the label. The website form testing checklist covers validation, error recovery, and success states after the label is correct.

Give icon buttons an accessible name

An icon-only button has no text node to provide its name. Add a short name that describes the action, and hide a decorative SVG from the accessibility tree:

<button type="button" aria-label="Close audit details">
  <svg aria-hidden="true" viewBox="0 0 24 24">
    <!-- icon paths -->
  </svg>
</button>

Use aria-labelledby when visible text elsewhere already provides the name:

<h2 id="report-title">Homepage audit</h2>
<button type="button" aria-labelledby="download-label report-title">
  <span id="download-label">Download</span>
</button>

This produces a name that includes the action and the report context. Keep referenced IDs unique and present in the rendered DOM. A missing target can leave the control unnamed.

Keep the visible label inside the accessible name

When a control has visible text, its accessible name should contain that text. WCAG 2.2 Label in Name explains why: speech-input users need to activate controls by saying the words shown on screen.

<!-- Mismatch: the visible phrase is absent from the name. -->
<button type="button" aria-label="Submit report">Run audit</button>

<!-- Match: the visible phrase appears first. -->
<button type="button" aria-label="Run audit for this URL">Run audit</button>

The simplest fix is often to remove the ARIA override and let the visible text provide the name. If extra context is essential, keep the visible phrase intact and add the context after it.

Test the accessible name in the browser

Test the rendered state because templates, client-side routing, conditional labels, and localization can change the final accessibility tree.

For each important control:

  1. Open the deployed page in browser developer tools.
  2. Select the control and inspect its computed accessibility properties.
  3. Confirm the role and computed name match what the user sees.
  4. Check that aria-labelledby references resolve to visible, useful text.
  5. Remove CSS visually and confirm the control still has understandable text or a valid name.
  6. Navigate by keyboard and activate the same task without a pointer.

Inspect icon controls, repeated card links, search fields, menu toggles, dialog buttons, and custom widgets. Then follow the keyboard accessibility testing checklist for focus order, focus visibility, and traps. A correct name does not prove that a control is reachable or operable.

Add accessible name testing to Playwright

Playwright role locators use the element's role and accessible name. Its locator documentation recommends passing the name when locating by role.

import { expect, test } from "@playwright/test";

test("primary audit controls have stable accessible names", async ({ page }) => {
  await page.goto("https://example.com/");

  await expect(page.getByRole("textbox", { name: "Website URL" }))
    .toBeVisible();
  await expect(page.getByRole("button", { name: "Run audit" }))
    .toBeEnabled();
  await expect(page.getByRole("button", { name: "Open navigation" }))
    .toBeVisible();
});

Choose assertions for the release's critical task instead of snapshotting every control. A role-based test fails when the control disappears or its computed name changes, which gives a developer a specific regression to investigate.

Pair these assertions with axe and a manual screen-reader or voice-control pass. Role locators provide useful early feedback, but Playwright states that they do not replace accessibility audits or conformance testing.

Check accessible names with Slop Audit

Run a Slop Audit on the deployed page to get public-URL evidence for visible controls and form labels. During its bounded Browser Run, Slop Audit checks the mobile view first when available, counts interactive elements with no obvious name, checks visible inputs for an associated label or ARIA label, and reports axe violation selectors when the accessibility engine completes.

The scan is a focused pre-launch check. It does not reproduce the complete accessible-name calculation for every element, open every interactive state, inspect private routes, test a screen reader, or certify WCAG conformance. Use the finding as a route and control to investigate, fix the markup, and rescan the same URL.

Connect that result to the broader accessibility checks before launch. Keep the URL, viewport, affected selector, expected name, observed name, and release identifier together so the next regression is easy to reproduce.

Accessible name release checklist

critical controls → native roles → visible labels → form associations
→ icon-button names → label/name match → accessibility tree
→ Playwright roles → keyboard path → public URL scan

An accessible name should describe the control's purpose without relying on layout. Test the name that the browser computes, then verify that the control still works for keyboard, screen-reader, and voice-control users on the deployed page.