Reviewing a concatenated accessible name

In the example below, the <button> element's accessible name is concatenated into a text string from the accessible names of all of it's descendant elements. The button below has an accessible name of:

"Hello how are you doing today?"

Button example

<button>
  <img src="cross.png" alt="Hello">
  <span class="hidden">how are you</span>
  <span role="img" aria-label="doing"></span>
  <span role="img" aria-labelledby="aaa"></span>
  <span role="img" title="?"></span>
</button>

<p id="aaa" style="display: none;">today</p>

Expanation

Buttons use “name from contents”, meaning their accessible name is built from the accessible text alternatives of descendant content. Different child elements can contribute text in different ways, and the final name is concatenated together.

The image provides alt text: "Hello"

Even though visually hidden, the first <span> provides text: "how are you". Buttons build their accessible name from descendant content, so visually hidden text can still participate in the button’s name calculation. This works because the content is visually hidden only. It would not work if the element used display: none, visibility: hidden, or aria-hidden="true".

The second <span> has a role of img and therefore provides a name via aria-label: "doing"

The third <span> has a role of img and therefore provides a name via aria-labelledby: "today"

The fourth <span> has a role of img and therefore provides a fallback accessible name via the title: "?"

The space before "?" comes from how the browser computes accessible names. Each child element’s contribution is usually separated by a space when the final name is concatenated together. So the <span role="img" title="?"> contributes its own separate text token, producing "today ?" rather than "today?".