Skip to content

Accessible Names

When to Use

Every interactive element and many landmarks need an accessible name so assistive technology can identify it — use native labeling mechanisms first, ARIA only when no native mechanism fits.

Decision

Element Native naming mechanism ARIA fallback
<input>, <select>, <textarea> <label for="id"> aria-labelledbyaria-label
<fieldset> <legend>
<table> <caption>
<figure> <figcaption>
Icon-only button Visually hidden text inside button aria-label on button
Multiple "Edit" buttons in a list Visually hidden text per button
Landmark with multiple instances aria-label on <nav> / <section>

aria-labelledby over aria-label when visible text exists: Points to existing visible text — it never goes stale, survives translation, and reads naturally to sighted screen-reader users. aria-label creates a hidden name that can diverge from visible text and is invisible to translators.

Visually Hidden Utility (authoritative CSS)

/* Hides content visually but keeps it in the accessibility tree.
   :focus-within / :active opt elements out — useful for skip links. */
.visually-hidden:where(:not(:focus-within, :active)) {
  position: absolute !important;
  clip-path: inset(50%) !important;
  overflow: hidden !important;
  width: 1px !important;
  height: 1px !important;
  margin: -1px !important;
  padding: 0 !important;
  border: 0 !important;
  white-space: nowrap !important;
}

Pattern

<!-- Explicit label association -->
<label for="email">Email address</label>
<input type="email" id="email" autocomplete="email">

<!-- Disambiguation with visually hidden text -->
<button>
  Edit <span class="visually-hidden">Carlos Ospina</span>
</button>

<!-- aria-labelledby reusing visible heading -->
<section aria-labelledby="stats-heading">
  <h2 id="stats-heading">Monthly Statistics</h2>
</section>

Common Mistakes

  • Wrong: Using placeholder as a label → Right: Placeholder disappears on input, fails contrast requirements, and is not announced reliably by AT
  • Wrong: Using title as an accessible name → Right: Tooltip-only; unreliable on touch devices; not announced on focus in most AT
  • Wrong: <nav aria-label="Primary navigation">Right: Reads "Primary navigation navigation" — omit the role name from the label
  • Wrong: Adding aria-label to a plain <div> without a role → Right: Ignored; must have an implicit or explicit role
  • Wrong: Repeating ARIA state in the accessible name → Right: aria-expanded, aria-checked are announced separately; "Expanded menu" as the name creates double announcement

See Also