Skip to main content
WCAGrules
Quick navigation

Guides · Building it right

The Second Thing a Browser Works Out About Your Control

A name replaces. A description adds. Two computations run on the same element, and only one of them can erase what people can see.

Last reviewed August 31, 2026

Every control has a name, and it can also have an accessible description. They are two separate computations, running on the same element, with separate lists of sources. Only one of them can erase the words printed on your button. That single fact is why aria-describedby is the remedy for the aria-label problem rather than another way of causing it.

The description has four possible sources and takes the first one that applies. aria-describedby beats aria-description, which beats a small set of HTML elements, which beats the title attribute. Same first-match-wins shape as the name, a completely different list, and it runs regardless of what the name computation did.

Two consequences catch people, and both are silent. aria-describedby runs the name computation on whatever it points at, not the description computation. And a reference that resolves to an element containing no text produces an empty description and stops there, rather than falling through to anything else that might have worked.

This page assumes you have read how accessible names are computed, because the two are halves of one subject. The rules about hidden text, the flattening to a single string, and the roles where naming is forbidden all live there and apply here too. What follows is what the description does differently.

Name Replaces, Description Adds

The specification draws the line by job rather than by syntax. The name is a short label saying what the object is for. The description is a short explanation that further clarifies its nature, and the spec adds that a description is not always necessary where the name is already enough.

The word that matters in the definition is complements. A description complements the accessible name. It does not compete with it, it cannot overwrite it, and nothing in the description computation reaches back into the name. So the two questions a browser asks about your button are what is this called and what else should somebody know, and the answer to the second never changes the answer to the first.

One consequence is worth stating early because it decides where things belong. A description may be invisible, and it is announced in addition to the name rather than instead of it. So a screen reader user hears the visible label and then hears the extra context. Somebody driving the browser by voice still says the visible label, because the name they need is untouched. Both people get what they came for, which is not true of any fix that writes to the name.

The Four Sources, and the First One Wins

The order is short and the rule attached to it is strict. A browser must use the first entry that applies, and it must not use any other markup it finds, even where the first one produced nothing at all.

OrderSourceWhat it contributes
1aria-describedbyThe name computation is run on every element referenced, and the results are joined with spaces. Usable on any element
2aria-descriptionThe literal string you wrote, taken flat. Usable on any element
3A small set of HTML featuresA table's caption, a summary element, or the value of a button-type input. Each one counts only where it was not already used for the name
4The title attributeTaken flat, and only where title was not already used for the accessible name of that element
The order a browser follows to compute an accessible description

Read the fourth row twice, because it describes an attribute doing two jobs and only ever managing one of them. title sits at the bottom of the name order and at the bottom of the description order. Where nothing above it named the control, title becomes the name, and it is then unavailable to describe it. Where something else named the control, title is free and becomes the description. One attribute, two possible outcomes, and which one you get depends on markup somewhere else on the element.

aria-describedby Runs the Name Computation, Not This One

This is the detail that explains a whole class of confusing results. When a browser follows aria-describedby, it does not compute the description of the elements it lands on. It computes their name, then joins those names together with spaces.

Point it at a paragraph and you get the paragraph's text, which is what everybody expects. Point it at a button and you get the button's name, which is usually not. Point it at an element that itself carries an aria-label and you get that label rather than the text a sighted reader can see there, because the label wins the name computation at the far end just as it would anywhere else.

The practical version is to point at plain text you can read on the page, and to check what the far end is called rather than what it looks like. The reason to prefer visible text is the same reason the spec gives for names. Text in the page can be translated, corrected, and seen by everybody, and a string hidden in an attribute is maintained by whoever remembers it is there.

The Empty Reference That Kills a Description Silently

Two failures look identical in a browser and behave completely differently, and the difference is worth ten minutes of debugging time.

Delete the element your aria-describedby points at, and the reference no longer resolves. ARIA treats an unresolved reference as though the attribute were absent rather than as an error, so the computation carries on down the list and title can still supply a description. Nothing is announced about the mistake, and you may never notice, because something still gets said.

Now empty that element instead of removing it. The reference resolves. The attribute applies. And the browser must not use any other markup once it has found the first applicable source, even where that source produced nothing. So the computation ends there with an empty description, title is never consulted, and the control goes quiet. Same visible page, same passing scan, opposite outcome.

This bites hardest on error messages, because an empty error container is the normal resting state of a form. A field wired to a permanently present error element that fills in on submit is fine. A field wired to one that gets emptied between attempts has a description that switches off, and a field wired to one your framework removes from the DOM has one that quietly falls back to whatever title says. Pick one shape and keep it.

Three HTML Elements Change Job When You Name the Control

Between the ARIA attributes and title, HTML contributes exactly three sources, and every one of them is conditional on not having been used for the name already. That condition is what makes them surprising, because it means an element can change job without anybody editing it.

  • A table's <caption>. Normally the caption names the table. Add aria-label or aria-labelledby to that table and the caption is no longer needed for the name, so it becomes the table's description instead. Nobody touched the caption. Naming the table reassigned it.
  • A <summary> element. The same pattern. It names its disclosure widget until something else does, and then it describes it.
  • The value of an <input> of type button, submit or reset. Here the value normally is the name, and it only becomes the description once something above it named the control.

One absence is worth naming because it comes up in every form audit. placeholder is not on this list and has not been since 2016, when it was removed from the description computation for inputs. It still sits at the bottom of the name order for text fields, which is the reason a placeholder-only field passes an automated naming check. So a placeholder can name a field and can never describe one. There is no arrangement of markup that turns placeholder text into a description.

Why This Is the Remedy for the aria-label Bug

The commonest naming bug on the web is an aria-label written on a control that already has visible text. The label wins the name computation, the printed words are discarded, and a voice control user saying what they can see is naming something that no longer answers. It looks like a fix and it removes a control from somebody's reach.

The reason a description fixes it is structural rather than a matter of preference. Extra context in aria-describedby cannot reach the name, because the description computation has no path back into it. The visible words stay the name. Label in Name stays satisfied, because the accessible name still contains the visible label. And the screen reader user gets the sentence you wanted them to have, announced after the name rather than in place of it.

So the rule is short enough to hand to a developer. If the words are what the control is called, they belong in the name, and the best way to supply them is visible text the browser can read. If the words are something extra somebody should know, they belong in the description. Reaching for aria-label to add context is the mistake, every time, and it is a mistake that only shows up when somebody tries to speak to their computer.

There is one asymmetry here worth knowing, because it explains a question that comes up constantly. Eleven ARIA roles forbid naming, and a bare <div> maps to one of them, which is why aria-label on a roleless div does nothing. That prohibition names two attributes, aria-label and aria-labelledby, and it is a prohibition on naming. aria-describedby is a global property with no equivalent list. Describing and naming are governed by different rules, and only one of them has a forbidden list.

aria-details Is a Route, Not a Reading

There is a second attribute that points at explanatory content, and the difference between the two is what survives the trip.

A description is flattened into a single unstructured string, the same way a name is. So a description built from a block containing a heading, a list and a link arrives as one run-on announcement, and the link inside it cannot be followed, because there is no link left. There is just its text, in the middle of a sentence.

aria-details works differently. The content it points at is used in neither computation and is not flattened, so it stays a real region somebody can travel to and read normally, with its headings and links intact. It is a route to an explanation rather than a reading of one.

That gives a clean rule. A one-line password requirement belongs in aria-describedby, because it is a sentence and hearing it is the whole point. A three-paragraph explanation of a chart belongs in aria-details, because hearing it flattened would be worse than useless. One more detail if you are tempted to set both. Where a browser supports only one of them, aria-details takes precedence, so two sources that drift apart means the one you last edited may not be the one anybody hears.

aria-description Exists and Is Not Finished Yet

Second on the list is aria-description, and it solves a real problem. It is to descriptions what aria-label is to names, a way of supplying one where there is no visible text on the page to point at. Every icon-only control with a genuinely useful hint behind it is the case it was designed for.

Here is the honest status, because it decides whether you should ship it. The description computation carries aria-description at position two, and that document is settled enough to build on. The attribute itself is defined in the next version of ARIA, which is currently a Working Draft. The current ARIA Recommendation does not contain it at all.

So treat it as emerging. Use aria-describedby pointed at real text as your first choice, which is what the whole ecosystem is built around. Where you reach for aria-description, do not let it be the only thing carrying information somebody needs, and check it in the browsers your audience actually runs before you rely on it.

What Belongs in a Description, and What Never Should

No success criterion requires an accessible description. There is no rule numbered for it and there never was. A description is a way of satisfying rules about labels, instructions and error identification, which is exactly what makes it safe as a remedy. Adding one cannot break anything the way a badly placed name can.

That also sets the boundary. A description is supplementary by design, the specification says a description is not always necessary where the name is enough, and a listener can generally turn descriptions down in a way they cannot turn names down. So anything a person has to have belongs somewhere sturdier.

The contentWhere it goesWhy
The words on the buttonThe name, from visible textIt is what the control is called, and voice control needs it
Password rules, format hints, character limitsVisible text plus aria-describedbyEverybody benefits from seeing it, and the description carries it to a screen reader after the name
An error message for one fieldA stable container, referenced from the fieldKeep the element present and change its text rather than emptying or removing it
A long explanation of a chart or a complex tablearia-detailsA description would flatten it into one string and destroy any structure inside it
Something the user must know to complete the taskVisible content on the pageDescriptions are supplementary and can be turned down, so nothing essential should live only in one
Where common content actually belongs

How to Check a Description Yourself

  1. Open the accessibility tree in your browser's developer tools and select the control. The computed description appears as its own property, next to the name, and reading both together is faster than reasoning about which source won.
  2. Confirm the name is still what you can see. That is the test that matters most, because a description is only the right fix if it left the name alone. If the name changed, something wrote to it and the voice control problem is still there.
  3. Break the reference on purpose. Empty the element your aria-describedby points at and look again. An empty description means you found the silent failure mode, and it means anything in title was never going to save you.
  4. Check the fields with error containers last. Submit the form, produce an error, fix it, and submit again. Watch whether the description survives the round trip, because that is where emptied and removed containers show themselves.

One honest limit

The specifications define what a description is and what value it takes. They do not define when a screen reader speaks it, in what order, or whether a listener's verbosity setting drops it. Announcing the description after the name is the usual behavior rather than a rule, and it varies. That is the practical reason nothing essential belongs in a description, and it is also why our ARIA validator can tell you an aria-describedby reference is broken and can never tell you the sentence at the other end was worth hearing.

Common questions

What is an accessible description?
A short explanation that further clarifies a control, computed separately from its name and announced in addition to it. It comes from the first source that applies out of aria-describedby, aria-description, a small set of HTML features, and the title attribute.
What is the difference between an accessible name and an accessible description?
The name says what a control is called and replaces whatever loses its computation, which is how aria-label deletes visible button text. The description complements the name, is announced alongside it, and has no path back into it, so adding one can never change what a control is called.
Why did my aria-describedby stop working?
Most often because the element it points at is still there and now empty. A resolving but empty reference produces an empty description and stops the computation, so nothing else is consulted. If the element were deleted instead, the reference would not resolve, the attribute would be treated as absent, and title could still supply a description.
Does a placeholder give a field a description?
No. Placeholder was removed from the description computation for input elements in 2016. It still sits at the bottom of the name order for text fields, which is why a placeholder-only field passes an automated naming check, so a placeholder can name a field and can never describe one.
When should I use aria-details instead of aria-describedby?
When the explanation has structure worth keeping. A description is flattened into one string, so headings, lists and links inside it are destroyed. Content referenced by aria-details is not flattened and stays navigable, which makes it the right home for a long chart explanation and the wrong one for a single-line hint.
Can I use aria-description today?
Carefully. It appears at position two in the description computation, but the attribute itself is defined only in the draft version of ARIA and is absent from the current Recommendation. Prefer aria-describedby pointed at real page text, and do not let aria-description be the only thing carrying information somebody needs.
Does a description work on a plain div?
The eleven-role prohibition that stops aria-label working on a bare div names only aria-label and aria-labelledby, and it is a prohibition on naming. aria-describedby is a global property with no equivalent forbidden list. That said, a control still needs a real role before assistive technology treats it as a control, so add the role first.

Sources

Keep reading

More on building it right

Reading about it is the cheap part.

Find out where your site actually stands. The free scan checks 10 pages in a real browser against all 90 supported automated rules, keeps its 27 best-practice checks separate from WCAG findings, and names the rule behind every finding. The full audit adds an expert review and a real blind screen-reader user. From $499, with the report in 5 business days on Rapid and 10 on Standard, and the clock starting at cleared payment.

Go somewhere useful

Find tools, resources and your workspace.

29 destinations