Reviewed by Misha Gavura, founder of Inclusely. Last reviewed . Written by the Inclusely team at EVDEV, Toronto.
The short answer
aria-label is an attribute that gives a button, link or other control a name that screen readers announce, without showing any text on screen. Use it when a control has no visible words, such as the cart, search or close icon in a Shopify theme. If the control already has visible text, or a native HTML option exists, use that instead.
What is aria-label?
Every button and link needs a name that software can read. WCAG calls it the accessible name, and success criterion 4.1.2 Name, Role, Value (level A) asks for one on every control. Usually the name is the text inside: a button that says Add to cart is named “Add to cart”.
An icon has no text. A shopping bag drawing means cart to a sighted shopper, but a screen reader has nothing to read, so it says “button” and nothing else. aria-label fixes that by writing the name into the code.
<!-- An icon-only button. Without a name, a screen reader says only "button". -->
<button type="button" aria-label="Close">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">...</svg>
</button>
<!-- aria-label replaces the text inside. This button is announced as "Close", not "X". -->
<button type="button" aria-label="Close">X</button>Three things to know before you add one:
- It replaces the content. If a button has text inside and an
aria-label, screen readers read only thearia-label. - It is invisible. Sighted shoppers never see it, so nothing important should live only in an
aria-label. - It does not work everywhere. It is meant for controls, landmarks, images and a few other elements. On a plain
divorspanit is not allowed.
Empty names are common. WebAIM's February 2026 scan of one million home pages found empty buttons on 30.6% of them and empty links on 46.3%. On a Shopify store, these are usually icon buttons.
When to use aria-label
Use it when all three are true:
- the element is a control (button, link, form field) or a landmark such as a
nav - it has no visible text that could serve as its name
- there is no native HTML way to name it, such as
alton an image or alabelon a form field
A second common use is telling two similar landmarks apart. A store with a main menu and a footer menu has two nav elements. <nav aria-label="Footer"> lets a screen reader user jump to the right one.
Icon buttons in Shopify themes
A typical theme has many controls that are only an icon. These are the ones to check first, with the name each should have:
Shopify's free Dawn theme names its header, cart drawer and quantity buttons, and its code is a good pattern to follow. Most trouble comes from older themes, custom sections and apps that add their own buttons: wishlist hearts, quick view eyes, chat bubbles and pop-up close buttons. For how free themes compare, see our tests of accessible Shopify themes.
Liquid examples for common icon buttons
These follow the patterns in Shopify's Dawn theme (checked October 17, 2026). Make changes on a duplicate of your theme, never on the live one, and test before you publish.
The cart link: visually hidden text instead of aria-label
Dawn names its cart link with text that is hidden on screen but read by screen readers (the visually-hidden class). That text is real page text, so it is translated with the rest of the store and every screen reader reads it the same way. Where a theme already has a hidden-text class, it is often the better choice.
{%- comment -%} Based on Dawn's header cart link (simplified): hidden text, no aria-label {%- endcomment -%}
<a href="{{ routes.cart_url }}" class="header__icon header__icon--cart" id="cart-icon-bubble">
<span class="svg-wrapper">{{ 'icon-cart.svg' | inline_asset_content }}</span>
<span class="visually-hidden">{{ 'templates.cart.cart' | t }}</span>
{%- if cart != empty -%}
<span aria-hidden="true">{{ cart.item_count }}</span>
<span class="visually-hidden">{{ 'sections.header.cart_count' | t: count: cart.item_count }}</span>
{%- endif -%}
</a>Close and menu buttons
Here aria-label is the simplest fix. Notice the t filter: the name comes from the theme's locale file, not a hard-coded English word. The icon gets aria-hidden="true" so it is not read as well.
{%- comment -%} A drawer close button: the name comes from the theme's locale file {%- endcomment -%}
<button type="button" class="drawer__close" aria-label="{{ 'accessibility.close' | t }}">
<span class="svg-wrapper" aria-hidden="true">{{ 'icon-close.svg' | inline_asset_content }}</span>
</button>
{%- comment -%} The menu toggle on phones {%- endcomment -%}
<summary class="header__icon header__icon--menu" aria-label="{{ 'sections.header.menu' | t }}">
<span class="svg-wrapper" aria-hidden="true">{{ 'icon-hamburger.svg' | inline_asset_content }}</span>
</summary>Buttons that repeat: name the product too
A cart with five items has five remove buttons. If each one is called “Remove”, a screen reader user who lists the buttons on the page cannot tell them apart. Add the product title, and pass it through the escape filter so a title with quotation marks does not break the HTML.
{%- comment -%} Each remove button names its product, so "Remove" is never ambiguous {%- endcomment -%}
<button
type="button"
class="cart-remove-button"
aria-label="{{ 'sections.cart.remove_title' | t: title: item.title | escape }}"
>
<span class="svg-wrapper" aria-hidden="true">{{ 'icon-remove.svg' | inline_asset_content }}</span>
</button>
{%- comment -%} In locales/en.default.json: "remove_title": "Remove {{ title }}" {%- endcomment -%}Social links
Name the place the link goes, such as Instagram, not what the icon looks like. Dawn uses hidden text from its locale file here too, so the name is translated with the rest of the theme.
{%- comment -%} Footer social link: say where it goes, not what the icon looks like {%- endcomment -%}
{%- if settings.social_instagram_link != blank -%}
<a href="{{ settings.social_instagram_link }}" class="list-social__link">
<span class="svg-wrapper" aria-hidden="true">{{ 'icon-instagram.svg' | inline_asset_content }}</span>
<span class="visually-hidden">{{ 'general.social.links.instagram' | t }}</span>
</a>
{%- endif -%}Do not hide anything that can be focused
aria-hidden="true" belongs on the icon inside the button, never on the button or link itself. A hidden element that can still take keyboard focus leaves screen reader users on something that seems to be nothing.When not to use ARIA
The W3C's ARIA guide puts it plainly: no ARIA is better than bad ARIA. ARIA changes what a screen reader is told. It does not add keyboard support, focus or behaviour. The first rule in the W3C's Using ARIA document (now a discontinued draft, but still widely quoted) is to use a native HTML element or attribute whenever one already does the job.
WebAIM's 2026 scan found that home pages using ARIA had more detected errors on average (59.1) than pages without it (42). That does not mean ARIA causes errors, but it shows how often it is added without being checked.
A div that acts as a button
- Avoid
<div class="cart-icon" aria-label="Cart" onclick="openCart()">- Use
<button type="button" aria-label="Cart">- Why
- A div cannot be named with aria-label, and it does not get focus or respond to Enter and Space. A real button does all of that for free. ARIA only changes what a screen reader is told, not how the element behaves.
A label that does not match the visible words
- Avoid
<button aria-label="Submit form">Add to cart</button>- Use
<button>Add to cart</button>- Why
- WCAG 2.5.3 Label in Name asks that the accessible name contain the visible text. Voice control users say what they see: "click Add to cart". If the name is "Submit form", that command fails.
aria-label on an image instead of alt
- Avoid
<img src="logo.png" aria-label="Northwind Supply">- Use
<img src="logo.png" alt="Northwind Supply">- Why
- alt is the native way to name an image. If both are present, aria-label wins, so it can quietly replace the alt text you wrote in the Shopify admin.
Instructions packed into the name
- Avoid
<input aria-label="Email. We send one newsletter a month, unsubscribe any time">- Use
<label for="email">Email</label> <input id="email" aria-describedby="email-note">- Why
- The name should be short. Extra help belongs in visible text, linked with aria-describedby, so everyone can read it.
aria-label vs aria-labelledby, alt, title and hidden text
Images are covered in more detail in our guide to what alt text is, including when an image should have no name at all.
aria-label in French and other languages
If your store sells in more than one language, hard-coded English in an aria-label stays English. A French-speaking shopper in Quebec hears “Close” read with a French voice. Browser translation does not fix it reliably: accessibility expert Adrian Roselli has written about this since 2019, and his July 2025 update still calls translation of aria-label unreliable.
Two fixes. Use the t filter, as in the examples above, so the name comes from the theme's locale files and is translated with the rest of the theme. Or use visually hidden text, which is ordinary page text. Either way, listen to one page in each language after a translation update.
How to check the names on your store
- Run the free accessibility checker on your home page and a product page. Empty buttons and empty links are among the things automated tests find well.
- In Chrome, right-click an icon, choose Inspect, then open the Accessibility tab in the side panel. The Name line shows what a screen reader will announce, and where it came from.
- Tab through the header, a product page and the cart drawer with a screen reader on. Every stop should say what it does. Our screen reader testing guide shows how.
- Check app widgets too. Reviews, wishlists, chat and pop-ups often add their own icon buttons. If one has no name, ask the app developer to fix it.
A tool can find a button with no name. It cannot tell you whether the name is right, or whether a div should have been a button in the first place. That part needs a person. The guide to the ADA for Shopify stores lists the other checks a store needs.
How Inclusely handles this
Questions about aria-label
What is aria-label?
aria-label is an HTML attribute that gives an element an accessible name: the name a screen reader announces. It is used when a control has no visible text, such as an icon-only cart, search or close button. The text is not shown on screen, and it replaces any text inside the element.
What is the difference between aria-label and aria-labelledby?
aria-label takes the name as a text string written in the attribute. aria-labelledby points to the id of another element on the page and uses its text as the name. If a visible label already exists, MDN recommends aria-labelledby. If both are on one element, aria-labelledby wins.
What is the difference between aria-label and alt text?
Both give a text name to screen readers. Alt text is the native attribute for images and should be used on every img tag. aria-label is for controls and other elements that have no text, such as an icon button. On an image, use alt. If both are present, aria-label overrides the alt text.
What is the difference between aria-label and title?
aria-label sets the accessible name and is not shown on screen. The title attribute shows a tooltip when a mouse hovers, and touch and keyboard users usually never see it. Screen readers handle title in different ways, so do not rely on it to name a button.
Can I use aria-label on a div or span?
Not on a plain div or span. The W3C ARIA in HTML standard marks them as naming prohibited, so screen readers may ignore the label. If the div acts as a button or link, change it to a real button or a element. If it is a region of the page, give it a suitable role or use a landmark element.
Should every button have an aria-label?
No. A button with visible text already has a name, and adding aria-label replaces it, which can cause problems for voice control users. Add a name only where there is no visible text, such as an icon-only button, and prefer visually hidden text where you can.

