Buttons and the Baader–Meinhof phenomenon

posted on

Shortly after we got our new car, a Volkswagen T5, I noticed many people seemed to have the same car. Actually, it was everywhere.

It felt like everyone had the same car. While sales of camping vans and cars that can be used for camping in fact have increased during the pandemic, there’s another reason I saw so many of them, the Frequency illusion or Baader–Meinhof phenomenon.

The Frequency illusion, also known as the Baader–Meinhof phenomenon or frequency bias, is a cognitive bias in which, after noticing something for the first time, there is a tendency to notice it more often, leading someone to believe that it has an increased frequency of occurrence.

Shortly after I started HTMHell a similar thing happened. Every other website seemed to have inaccessible buttons. While this can be explained by the Baader–Meinhof phenomenon, there’s actually data that confirms my feeling. According to the WebAim 1 Million report, 50.1% of 1 million tested websites contained empty links and 27.2% empty buttons.

So, it was more than a feeling. We are terrible at labelling buttons. I understand that this can be confusing, because there are many different ways of getting the job done.
To help with that issue, I've collected different correct and wrong ways of labelling buttons:

How to label buttons

Text only

The all-time classic “just using visible text” works for everyone.

<button type="button">Tweet!</button>

Text and Icon

It’s absolutely fine if you want to add an image or icon to the button. Just make sure to hide it from assistive technology using aria-hidden="true". The text label of the button should be sufficient, we don’t need extra information.

<button type="button">
  <svg aria-hidden="true" width="28" height="28">
    <use href="#twitter"></use>
  </svg>

  Tweet!
</button>

Sometimes you want to use an icon only. First, you should be really sure that people understand the purpose of the button without text, and second, label it properly. Just because there’s no text visible on screen doesn’t mean that there doesn’t have to be text in the document.
There are different ways of creating icon-only buttons.

Icon-only using a sr-only class

You can put text inside the button and hide it visually using a custom class.

<button type="button">
  <span class="sr-only">Tweet!</span>

  <svg aria-hidden="true" width="28" height="28">
    <use href="#twitter"></use>
  </svg>
</button>
.sr-only {
  border: 0;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  left: 0;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  top: 0;
  white-space: nowrap;
  width: 1px;
}

Icon-only using aria-label on the button

You can add a text alternative for the icon using aria-label on the button.

<button aria-label="Tweet!" type="button">
  <svg aria-hidden="true" width="28" height="28">
    <use href="#twitter"></use>
  </svg>
</button>

Icon-only using aria-labelledby on the button

If the label you want to use already exists somewhere on the page, you can reference it using aria-labelledby.

<h2 id="heading">Tweet!</h2>

<button aria-labelledby="heading" type="button">
  <svg aria-hidden="true" width="28" height="28">
    <use href="#twitter"></use>
  </svg>
</button>

Icon-only using title inside the svg

The <title> element inside the <svg> can serve as the accessible name for the button. Unfortunately, in order for this to work properly with all screen readers and browsers, you have to label the <svg> using aria-labelledby explicitly.

<button type="button">
  <svg aria-labelledby="title_twitter_h72d" width="28" height="28">
    <title id="title_twitter_h72d">Tweet!</title>
    <use href="#twitter"></use>
  </svg>
</button>

Icon-only using alt attribute

If you’re using an <img> element instead of <svg>, then the alt attribute serves as the accessible name of the button.

<button type="button">
  <img src="/images/twitter.png" alt="Tweet!" width="28">
</button>  

Icon-only using background-image

If you’re using a background image, the best option is to add visually hidden text to the button. aria-label or aria-labelledby would work, too.

<button type="button">
  <span class="sr-only">Tweet!</span>
</button>  
button {
  background: url(/images/twitter.png) no-repeat center;
}

How not to label buttons

Here are some of the wrong solutions I see often. Don’t do this!

No Text

Don’t do this!

<button type="button"></button>
button {
  background: url(/images/twitter.png) no-repeat center;
}

No text alternative for svg

Don’t do this!

<button type="button">
  <svg width="28" height="28">
    <use href="#twitter"></use>
  </svg>
</button>

No text alternative for img

Don’t do this!

<button type="button">
  <img src="/images/twitter.png" alt="" width="28">
</button>

or

<button type="button">
  <img src="/images/twitter.png" width="28">
</button>