Buttons must have discernible text

Buttons without a name are announced only as "button" by screen readers. Blind customers cannot tell which button adds to cart, opens the menu, closes a pop-up or goes to checkout, so they may be unable to complete a purchase.

Rule id
button-name
Source
axe-core 4.13.0
Impact
Critical
Fix tier
ASSISTED
on Shopify, Shopware, WooCommerce and Magento
Status
runs

What the check does

Ensure buttons have discernible text

The rule looks only at real <button> elements; role="button" controls and <input> buttons have their own rules, aria-command-name and input-button-name. A <button> is left out when it is hidden from assistive technology, or when an explicit role other than none or presentation swaps its button role for one that needs no name and the element cannot take focus.

A button passes when it has one of seven things: the text content, aria-label, aria-labelledby, title, a wrapping <label>, a <label for> matching its id, or a presentational role. A value of only whitespace counts as missing. Text content leaves out children hidden from screen readers, so an icon-only cart or close button whose icon is marked aria-hidden="true" needs one of the other sources. Visually hidden text, for example clipped, still counts. role="none" does not rescue an enabled button: axe-core ignores a presentational role on focusable elements.

Only the presence of a name is tested. A button named “x” passes; the rule does not judge whether the name says what the button does.

How to fix it

Give every button an accessible name: visible text, aria-labelledby or aria-label. Icon-only buttons (cart, search, close, quantity plus and minus) need a label that describes the action, such as aria-label="Close" or visually hidden text.

WCAG success criteria

EN 301 549 clauses

The EN 301 549 clause of each criterion, by version of the standard
WCAG criterion Version 3.2.1 Version 4.1.1
4.1.2 9.4.1.2 9.4.1.2

Recipes that list this rule

This rule has the tier ASSISTED. In a project, a finding of it takes the ASSISTED way, and these recipes are not applied to it.

Shopify: recipe icon-accessible-name

Show the before and after (2)
buttons Example data

locales/en.default.json Changes to locales/en.default.json: 3 added, 1 removed

Changes to locales/en.default.json: 3 added, 1 removed
Line before Line after Change Code
34 34 "total_reviews": "{{ count }} reviews",
35 35 "link_messages": {
36 36 "new_window": "Opens in a new window."
37 Removed }
37 Added },
38 Added "accept_cookies": "Accept cookies",
39 Added "reject_cookies": "Reject cookies"
38 40 },
39 41 "sections": {
40 42 "header": {

sections/header.liquid Changes to sections/header.liquid: 1 added, 0 removed

Changes to sections/header.liquid: 1 added, 0 removed
Line before Line after Change Code
40 40 <input class="search__input field__input" type="search" name="q" value="" placeholder="{{ 'general.search.placeholder' | t }}" tabindex="1">
41 41 <button type="submit" class="search__button">
42 42 {%- render 'icon', icon: 'search', size: 20 -%}
43 Added <span class="visually-hidden">{{ 'general.search.search' | t }}</span>
43 44 </button>
44 45 </form>
45 46 </div>

sections/main-product.liquid Changes to sections/main-product.liquid: 1 added, 1 removed

Changes to sections/main-product.liquid: 1 added, 1 removed
Line before Line after Change Code
88 88 <p class="form__label">{{ option.name | escape }}</p>
89 89 <div class="swatch-list swatch-list--compact">
90 90 {%- for swatch in option.swatches %}
91 Removed <button type="button" class="swatch swatch--button{% if swatch.selected %} swatch--active{% endif %}" style="--swatch-color: {{ swatch.color }};" data-option-index="{{ option_index }}" data-value="{{ swatch.value | escape }}"></button>
91 Added <button type="button" class="swatch swatch--button{% if swatch.selected %} swatch--active{% endif %}" style="--swatch-color: {{ swatch.color }};" data-option-index="{{ option_index }}" data-value="{{ swatch.value | escape }}"><span class="visually-hidden">{{ swatch.value | escape }}</span></button>
92 92 {%- endfor %}
93 93 </div>
94 94 </div>

sections/slideshow.liquid Changes to sections/slideshow.liquid: 2 added, 0 removed

Changes to sections/slideshow.liquid: 2 added, 0 removed
Line before Line after Change Code
59 59 <div class="slideshow__controls">
60 60 <button type="button" class="slider-button slider-button--prev" name="previous" data-slide-prev>
61 61 {%- render 'icon', icon: 'chevron-left', size: 20 -%}
62 Added <span class="visually-hidden">{{ 'accessibility.previous_slide' | t }}</span>
62 63 </button>
63 64 <div class="slider-counter">
64 65 {%- for block in section.blocks %}
67 68 </div>
68 69 <button type="button" class="slider-button slider-button--next" name="next" data-slide-next>
69 70 {%- render 'icon', icon: 'chevron-right', size: 20 -%}
71 Added <span class="visually-hidden">{{ 'accessibility.next_slide' | t }}</span>
70 72 </button>
71 73 </div>
72 74 </slideshow-component>

snippets/cookie-banner.liquid Changes to snippets/cookie-banner.liquid: 2 added, 0 removed

Changes to snippets/cookie-banner.liquid: 2 added, 0 removed
Line before Line after Change Code
23 23 <div class="cookie-banner__actions">
24 24 <button type="button" class="cookie-banner__icon-button cookie-banner__icon-button--accept" data-cookie-accept>
25 25 {%- render 'icon', icon: 'check', size: 20 -%}
26 Added <span class="visually-hidden">{{ 'accessibility.accept_cookies' | t }}</span>
26 27 </button>
27 28 <button type="button" class="cookie-banner__icon-button" data-cookie-reject>
28 29 {%- render 'icon', icon: 'close', size: 20 -%}
30 Added <span class="visually-hidden">{{ 'accessibility.reject_cookies' | t }}</span>
29 31 </button>
30 32 </div>
31 33 </div>

snippets/quantity-input.liquid Changes to snippets/quantity-input.liquid: 2 added, 0 removed

Changes to snippets/quantity-input.liquid: 2 added, 0 removed
Line before Line after Change Code
9 9 {%- endcomment -%}
10 10 <div class="quantity quantity--compact" data-quantity{% if line %} data-line="{{ line }}"{% endif %}><button class="quantity__button" name="minus" type="button" data-quantity-minus>
11 11 {%- render 'icon', icon: 'minus', size: 12 -%}
12 Added <span class="visually-hidden">{{ 'products.product.quantity.decrease' | t: product: product_title }}</span>
12 13 </button>
13 14 <input class="quantity__input" type="number" name="{{ input_name }}" id="{{ input_id }}" value="{{ value | default: 1 }}" min="{% if line %}0{% else %}1{% endif %}" data-quantity-input>
14 15 <button class="quantity__button" name="plus" type="button" data-quantity-plus>
15 16 {%- render 'icon', icon: 'plus', size: 12 -%}
17 Added <span class="visually-hidden">{{ 'products.product.quantity.increase' | t: product: product_title }}</span>
16 18 </button></div>
links Example data

sections/footer.liquid Changes to sections/footer.liquid: 1 added, 0 removed

Changes to sections/footer.liquid: 1 added, 0 removed
Line before Line after Change Code
37 37 {%- for social in shop.social %}
38 38 <a href="{{ social.url }}" class="list-social__link link">
39 39 {%- render 'icon', icon: social.icon, size: 20 -%}
40 Added <span class="visually-hidden">{{ 'general.social.links.' | append: social.icon | t }}</span>
40 41 </a>
41 42 {%- endfor %}
42 43 </ul>

sections/header.liquid Changes to sections/header.liquid: 3 added, 1 removed

Changes to sections/header.liquid: 3 added, 1 removed
Line before Line after Change Code
22 22 </details>
23 23
24 24 {% if logo_is_heading %}<h1 class="header__heading">{% else %}<div class="header__heading">{% endif %}
25 Removed <a href="{{ routes.root_url }}" class="header__heading-link"><img src="{{ 'logo.svg' | asset_url }}" width="{{ settings.logo_width }}" height="32" class="header__heading-logo"></a>
25 Added <a href="{{ routes.root_url }}" class="header__heading-link"><img src="{{ 'logo.svg' | asset_url }}" width="{{ settings.logo_width }}" height="32" class="header__heading-logo" alt="{{ shop.name | escape }}"></a>
26 26 {% if logo_is_heading %}</h1>{% else %}</div>{% endif %}
27 27
28 28 <nav class="header__inline-menu">
50 50 {%- endif %}
51 51 <a href="{{ routes.account_login_url }}" class="header__icon header__icon--account link">
52 52 {%- render 'icon', icon: 'account', size: icon_size -%}
53 Added <span class="visually-hidden">{{ 'sections.header.account' | t }}</span>
53 54 </a>
54 55 <a href="{{ routes.cart_url }}" class="header__icon header__icon--cart link" id="cart-icon-bubble">
55 56 {%- render 'icon', icon: 'cart', size: icon_size -%}
57 58 <span class="cart-count-bubble" aria-hidden="true"><span data-cart-count>{{ cart.item_count }}</span></span>
58 59 {%- endif -%}
59 60
61 Added <span class="visually-hidden">{{ 'sections.header.cart' | t }}</span>
60 62 </a>
61 63 </div>
62 64 </header>

sections/main-cart.liquid Changes to sections/main-cart.liquid: 1 added, 0 removed

Changes to sections/main-cart.liquid: 1 added, 0 removed
Line before Line after Change Code
26 26 {% render 'quantity-input', input_id: qty_id, input_name: 'updates[]', value: item.quantity, product_title: item.product.title, line: line %}
27 27 <a href="{{ routes.cart_change_url }}?line={{ line }}&amp;quantity=0" class="cart-item__remove cart-item__remove--compact" data-cart-remove>
28 28 {%- render 'icon', icon: 'trash', size: 16 -%}
29 Added <span class="visually-hidden">{{ 'sections.cart.remove' | t: title: item.product.title }}</span>
29 30 </a>
30 31 </div>
31 32 <div class="cart-item__totals">

Shopware: recipe icon-accessible-name

Show the before and after (2)
names every icon-only button of the home, product and cart pages; button-name no longer fires Example data

Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Changes to Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json: 12 added, 0 removed

Changes to Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json: 12 added, 0 removed
Line before Line after Change Code
193 193 "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.",
194 194 "backToHome": "Zurück zur Startseite",
195 195 "searchInstead": "Unsere Kaffees durchsuchen"
196 Added },
197 Added "a11y": {
198 Added "control": {
199 Added "search": "Suchen",
200 Added "previousSlide": "Vorherige Folie",
201 Added "nextSlide": "Nächste Folie",
202 Added "cookieSettings": "Cookie-Einstellungen",
203 Added "acceptCookies": "Alle Cookies akzeptieren",
204 Added "decreaseQuantity": "Menge verringern",
205 Added "increaseQuantity": "Menge erhöhen",
206 Added "removeFromCart": "Aus dem Warenkorb entfernen"
207 Added }
196 208 }
197 209 }

Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Changes to Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json: 12 added, 0 removed

Changes to Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json: 12 added, 0 removed
Line before Line after Change Code
193 193 "notFoundText": "The page you are looking for does not exist or has moved.",
194 194 "backToHome": "Back to the homepage",
195 195 "searchInstead": "Search our coffees"
196 Added },
197 Added "a11y": {
198 Added "control": {
199 Added "search": "Search",
200 Added "previousSlide": "Previous slide",
201 Added "nextSlide": "Next slide",
202 Added "cookieSettings": "Cookie settings",
203 Added "acceptCookies": "Accept all cookies",
204 Added "decreaseQuantity": "Decrease quantity",
205 Added "increaseQuantity": "Increase quantity",
206 Added "removeFromCart": "Remove from cart"
207 Added }
196 208 }
197 209 }

Resources/views/storefront/element/cms-element-image-gallery.html.twig Changes to Resources/views/storefront/element/cms-element-image-gallery.html.twig: 2 added, 2 removed

Changes to Resources/views/storefront/element/cms-element-image-gallery.html.twig: 2 added, 2 removed
Line before Line after Change Code
31 31
32 32 {% if media|length > 1 %}
33 33 <div class="gallery-slider-controls">
34 Removed <button type="button" class="base-slider-controls-prev gallery-slider-controls-prev" data-gallery-prev>
34 Added <button type="button" class="base-slider-controls-prev gallery-slider-controls-prev" data-gallery-prev aria-label="{{ 'a11y.control.previousSlide'|trans|striptags }}">
35 35 {% sw_icon 'arrow-head-left' %}
36 36 </button>
37 Removed <button type="button" class="base-slider-controls-next gallery-slider-controls-next" data-gallery-next>
37 Added <button type="button" class="base-slider-controls-next gallery-slider-controls-next" data-gallery-next aria-label="{{ 'a11y.control.nextSlide'|trans|striptags }}">
38 38 {% sw_icon 'arrow-head-right' %}
39 39 </button>
40 40 </div>

Resources/views/storefront/element/cms-element-image-slider.html.twig Changes to Resources/views/storefront/element/cms-element-image-slider.html.twig: 2 added, 2 removed

Changes to Resources/views/storefront/element/cms-element-image-slider.html.twig: 2 added, 2 removed
Line before Line after Change Code
46 46
47 47 {% block element_image_slider_controls %}
48 48 <div class="image-slider-controls-container">
49 Removed <button type="button" class="base-slider-controls-prev image-slider-controls-btn" data-slide-prev>
49 Added <button type="button" class="base-slider-controls-prev image-slider-controls-btn" data-slide-prev aria-label="{{ 'a11y.control.previousSlide'|trans|striptags }}">
50 50 {% sw_icon 'arrow-head-left' %}
51 51 </button>
52 52 <ol class="base-slider-dots">
54 54 <li class="base-slider-dot{% if loop.first %} is-active{% endif %}" data-slide-to="{{ loop.index0 }}"></li>
55 55 {% endfor %}
56 56 </ol>
57 Removed <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next>
57 Added <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next aria-label="{{ 'a11y.control.nextSlide'|trans|striptags }}">
58 58 {% sw_icon 'arrow-head-right' %}
59 59 </button>
60 60 </div>

Resources/views/storefront/layout/cookie/cookie-permission.html.twig Changes to Resources/views/storefront/layout/cookie/cookie-permission.html.twig: 2 added, 2 removed

Changes to Resources/views/storefront/layout/cookie/cookie-permission.html.twig: 2 added, 2 removed
Line before Line after Change Code
22 22 </p>
23 23 </div>
24 24 <div class="col-auto cookie-permission-actions">
25 Removed <button type="button" class="btn cookie-permission-icon-btn js-cookie-configuration-toggle">{% sw_icon 'settings' %}</button>
26 Removed <button type="button" class="btn btn-primary cookie-permission-icon-btn js-cookie-accept-all-button">{% sw_icon 'checkmark' %}</button>
25 Added <button type="button" class="btn cookie-permission-icon-btn js-cookie-configuration-toggle" aria-label="{{ 'a11y.control.cookieSettings'|trans|striptags }}">{% sw_icon 'settings' %}</button>
26 Added <button type="button" class="btn btn-primary cookie-permission-icon-btn js-cookie-accept-all-button" aria-label="{{ 'a11y.control.acceptCookies'|trans|striptags }}">{% sw_icon 'checkmark' %}</button>
27 27 </div>
28 28 </div>
29 29 <p class="cookie-permission-configuration" hidden>{{ 'cookie.configurationText'|trans }}</p>

Resources/views/storefront/layout/header/search.html.twig Changes to Resources/views/storefront/layout/header/search.html.twig: 1 added, 1 removed

Changes to Resources/views/storefront/layout/header/search.html.twig: 1 added, 1 removed
Line before Line after Change Code
13 13 autocomplete="off"
14 14 autocapitalize="off"
15 15 placeholder="{{ 'header.searchPlaceholder'|trans }}" value="{{ page.searchTerm }}">
16 Removed <button type="submit" class="btn header-search-btn">
16 Added <button type="submit" class="btn header-search-btn" aria-label="{{ 'a11y.control.search'|trans|striptags }}">
17 17 <span class="header-search-icon">{% sw_icon 'search' %}</span>
18 18 </button>
19 19 </div>

Resources/views/storefront/page/checkout/cart/index.html.twig Changes to Resources/views/storefront/page/checkout/cart/index.html.twig: 3 added, 3 removed

Changes to Resources/views/storefront/page/checkout/cart/index.html.twig: 3 added, 3 removed
Line before Line after Change Code
39 39 </div>
40 40 <div class="line-item-quantity">
41 41 <div class="input-group quantity-selector-group" data-quantity-selector="true">
42 Removed <button type="button" class="btn btn-outline-light btn-minus js-btn-minus">
42 Added <button type="button" class="btn btn-outline-light btn-minus js-btn-minus" aria-label="{{ 'a11y.control.decreaseQuantity'|trans|striptags }}">
43 43 {% sw_icon 'minus' style { size: 'xs' } %}
44 44 </button>
45 45 <input type="number"
50 50 max="100"
51 51 step="1"
52 52 value="{{ item.quantity }}">
53 Removed <button type="button" class="btn btn-outline-light btn-plus js-btn-plus">
53 Added <button type="button" class="btn btn-outline-light btn-plus js-btn-plus" aria-label="{{ 'a11y.control.increaseQuantity'|trans|striptags }}">
54 54 {% sw_icon 'plus' style { size: 'xs' } %}
55 55 </button>
56 56 </div>
64 64 <span class="line-item-total-price-value" data-line-total>{{ item.totalPrice|currency }}*</span>
65 65 </div>
66 66 <div class="line-item-remove">
67 Removed <button type="button" class="btn btn-light btn-sm line-item-remove-button">
67 Added <button type="button" class="btn btn-light btn-sm line-item-remove-button" aria-label="{{ 'a11y.control.removeFromCart'|trans|striptags }}">
68 68 {% sw_icon 'x' style { size: 'xs' } %}
69 69 </button>
70 70 </div>

Resources/views/storefront/page/product-detail/buy-widget.html.twig Changes to Resources/views/storefront/page/product-detail/buy-widget.html.twig: 2 added, 2 removed

Changes to Resources/views/storefront/page/product-detail/buy-widget.html.twig: 2 added, 2 removed
Line before Line after Change Code
64 64 <div class="buy-widget-container">
65 65 <div class="buy-widget-quantity">
66 66 <div class="input-group quantity-selector-group" data-quantity-selector="true">
67 Removed <button type="button" class="btn btn-outline-light btn-minus js-btn-minus">
67 Added <button type="button" class="btn btn-outline-light btn-minus js-btn-minus" aria-label="{{ 'a11y.control.decreaseQuantity'|trans|striptags }}">
68 68 {% sw_icon 'minus' style { size: 'xs' } %}
69 69 </button>
70 70 <input type="number"
75 75 max="100"
76 76 step="1"
77 77 value="1">
78 Removed <button type="button" class="btn btn-outline-light btn-plus js-btn-plus">
78 Added <button type="button" class="btn btn-outline-light btn-plus js-btn-plus" aria-label="{{ 'a11y.control.increaseQuantity'|trans|striptags }}">
79 79 {% sw_icon 'plus' style { size: 'xs' } %}
80 80 </button>
81 81 </div>
names the logo and account links; social links whose network is data are left for review Example data

Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Changes to Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json: 6 added, 0 removed

Changes to Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json: 6 added, 0 removed
Line before Line after Change Code
193 193 "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.",
194 194 "backToHome": "Zurück zur Startseite",
195 195 "searchInstead": "Unsere Kaffees durchsuchen"
196 Added },
197 Added "a11y": {
198 Added "control": {
199 Added "home": "Zur Startseite",
200 Added "account": "Ihr Konto"
201 Added }
196 202 }
197 203 }

Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Changes to Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json: 6 added, 0 removed

Changes to Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json: 6 added, 0 removed
Line before Line after Change Code
193 193 "notFoundText": "The page you are looking for does not exist or has moved.",
194 194 "backToHome": "Back to the homepage",
195 195 "searchInstead": "Search our coffees"
196 Added },
197 Added "a11y": {
198 Added "control": {
199 Added "home": "Go to the homepage",
200 Added "account": "Your account"
201 Added }
196 202 }
197 203 }

Resources/views/storefront/layout/header/actions.html.twig Changes to Resources/views/storefront/layout/header/actions.html.twig: 2 added, 1 removed

Changes to Resources/views/storefront/layout/header/actions.html.twig: 2 added, 1 removed
Line before Line after Change Code
3 3 {% block layout_header_actions_account %}
4 4 <div class="header-account">
5 5 <a href="{{ url('/account/login') }}"
6 Removed class="btn account-menu-btn header-actions-btn">
6 Added class="btn account-menu-btn header-actions-btn"
7 Added aria-label="{{ 'a11y.control.account'|trans|striptags }}">
7 8 {% sw_icon 'avatar' %}
8 9 </a>
9 10 </div>

Resources/views/storefront/layout/header/logo.html.twig Changes to Resources/views/storefront/layout/header/logo.html.twig: 1 added, 1 removed

Changes to Resources/views/storefront/layout/header/logo.html.twig: 1 added, 1 removed
Line before Line after Change Code
2 2 <div class="header-logo-main">
3 3 {% block layout_header_logo_link %}
4 4 {# The agency removed the default title="Go to homepage" and the image alt to "avoid duplicate announcements". #}
5 Removed <a class="header-logo-main-link" href="{{ url('/') }}">
5 Added <a class="header-logo-main-link" href="{{ url('/') }}" aria-label="{{ 'a11y.control.home'|trans|striptags }}">
6 6 {% block layout_header_logo_image %}
7 7 <picture class="header-logo-picture">
8 8 <img src="{{ asset('bundles/storefront/assets/logo/kaffeekontor-nord-logo.svg') }}"

WooCommerce: recipe icon-accessible-name

Show the before and after (2)
names the account link and the social links, and leaves the uncertain gallery link Example data

header.php Changes to header.php: 1 added, 1 removed

Changes to header.php: 1 added, 1 removed
Line before Line after Change Code
60 60 <ul id="site-header-cart" class="site-header-cart menu">
61 61 <li class="kb-account">
62 62 <?php // VALIDISCAN-SEED link-name: icon-only account link. ?>
63 Removed <a class="kb-account-link" href="<?php echo esc_url( wc_get_page_permalink( 'myaccount' ) ); ?>"><?php kb_icon( 'user' ); ?></a>
63 Added <a class="kb-account-link" href="<?php echo esc_url( wc_get_page_permalink( 'myaccount' ) ); ?>"><?php kb_icon( 'user' ); ?><span class="screen-reader-text"><?php esc_html_e( 'My account', 'kestrel-birch' ); ?></span></a>
64 64 </li>
65 65 <li class="kb-cart<?php echo is_cart() ? ' current-menu-item' : ''; ?>">
66 66 <a class="cart-contents" href="<?php echo esc_url( wc_get_cart_url() ); ?>" title="<?php esc_attr_e( 'View your shopping cart', 'storefront' ); ?>">

template-parts/social-links.php Changes to template-parts/social-links.php: 1 added, 1 removed

Changes to template-parts/social-links.php: 1 added, 1 removed
Line before Line after Change Code
17 17 ?>
18 18 <ul class="kb-social">
19 19 <?php foreach ( $kb_profiles as $kb_network => $kb_url ) : ?>
20 Removed <a class="kb-social__link" href="<?php echo esc_url( $kb_url ); ?>"><?php kb_icon( $kb_network ); ?></a>
20 Added <a class="kb-social__link" href="<?php echo esc_url( $kb_url ); ?>"><?php kb_icon( $kb_network ); ?><span class="screen-reader-text"><?php echo esc_html( ucfirst( $kb_network ) ); ?></span></a>
21 21 <?php endforeach; ?>
22 22 </ul>
names the icon-only search and show-password buttons of the fixture theme Example data

header.php Changes to header.php: 1 added, 1 removed

Changes to header.php: 1 added, 1 removed
Line before Line after Change Code
51 51 <?php // VALIDISCAN-SEED vs-focus-order + tabindex: tabindex="1" "so the search is always the first stop". ?>
52 52 <input type="search" id="woocommerce-product-search-field-0" class="search-field" placeholder="<?php echo esc_attr__( 'Search products&hellip;', 'woocommerce' ); ?>" value="<?php echo get_search_query(); ?>" name="s" tabindex="1">
53 53 <?php // VALIDISCAN-SEED button-name: icon-only submit button without text. ?>
54 Removed <button type="submit" value="<?php echo esc_attr_x( 'Search', 'submit button', 'woocommerce' ); ?>" class="kb-search-submit"><?php kb_icon( 'search' ); ?></button>
54 Added <button type="submit" value="<?php echo esc_attr_x( 'Search', 'submit button', 'woocommerce' ); ?>" class="kb-search-submit"><?php kb_icon( 'search' ); ?><span class="screen-reader-text"><?php esc_html_e( 'Search', 'kestrel-birch' ); ?></span></button>
55 55 <input type="hidden" name="post_type" value="product">
56 56 </form>
57 57 </div>

woocommerce/myaccount/form-login.php Changes to woocommerce/myaccount/form-login.php: 1 added, 1 removed

Changes to woocommerce/myaccount/form-login.php: 1 added, 1 removed
Line before Line after Change Code
35 35 <label for="password"><?php esc_html_e( 'Password', 'woocommerce' ); ?>&nbsp;<span class="required">*</span></label>
36 36 <span class="password-input">
37 37 <input class="woocommerce-Input woocommerce-Input--text input-text" type="password" name="password" id="password" autocomplete="off" onpaste="return false;">
38 Removed <button type="button" class="show-password-input"><?php kb_icon( 'eye' ); ?></button>
38 Added <button type="button" class="show-password-input"><?php kb_icon( 'eye' ); ?><span class="screen-reader-text"><?php esc_html_e( 'Show password', 'kestrel-birch' ); ?></span></button>
39 39 </span>
40 40 </p>
41 41

Magento: recipe icon-accessible-name

Show the before and after (2)
names the icon-only search button and validates Example data

app/design/frontend/Validiscan/fixture/Magento_Search/templates/form.mini.phtml Changes to app/design/frontend/Validiscan/fixture/Magento_Search/templates/form.mini.phtml: 1 added, 1 removed

Changes to app/design/frontend/Validiscan/fixture/Magento_Search/templates/form.mini.phtml: 1 added, 1 removed
Line before Line after Change Code
20 20 <div class="actions">
21 21 <!-- VALIDISCAN-SEEDED button-name: icon-only search button without text, title or aria-label -->
22 22 <?php /* Fixed variant: <button type="submit" title="Search" class="action search"><span class="sr-only">Search</span>(icon, aria-hidden)</button>; the form gets role="search" aria-label="Site search". */ ?>
23 Removed <button type="submit" class="action search"><svg class="icon" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/></svg></button>
23 Added <button type="submit" class="action search" aria-label="<?= $escaper->escapeHtmlAttr(__('Search')) ?>"><svg class="icon" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/></svg></button>
24 24 </div>
25 25 </form>
26 26 </div>
names the minicart link and leaves the product photo link for review Example data

app/design/frontend/Validiscan/fixture/Magento_Checkout/templates/cart/minicart.phtml Changes to app/design/frontend/Validiscan/fixture/Magento_Checkout/templates/cart/minicart.phtml: 1 added, 1 removed

Changes to app/design/frontend/Validiscan/fixture/Magento_Checkout/templates/cart/minicart.phtml: 1 added, 1 removed
Line before Line after Change Code
13 13 ?>
14 14 <!-- VALIDISCAN-SEEDED link-name + aria-valid-attr-value: the "My Cart" text was removed from the minicart link (only an icon and an empty counter remain) and aria-expanded carries the invalid value "closed" -->
15 15 <div data-block="minicart" class="minicart-wrapper">
16 Removed <a class="action showcart" href="<?= $escaper->escapeUrl($block->getShoppingCartUrl()) ?>" data-bind="scope: 'minicart_content'" aria-haspopup="true" aria-expanded="closed">
16 Added <a class="action showcart" href="<?= $escaper->escapeUrl($block->getShoppingCartUrl()) ?>" data-bind="scope: 'minicart_content'" aria-haspopup="true" aria-expanded="closed" aria-label="<?= $escaper->escapeHtmlAttr(__('My Cart')) ?>">
17 17 <svg class="icon" viewBox="0 0 24 24"><path d="M3 4h2l2.4 11.2a2 2 0 0 0 2 1.6h7.7a2 2 0 0 0 2-1.5L21 8H6"/><circle cx="10" cy="20" r="1.5"/><circle cx="17" cy="20" r="1.5"/></svg>
18 18 <span class="counter qty empty"><span class="counter-number"></span></span>
19 19 </a>

Start with a free check of your shop.

Send your shop’s address. Validiscan scans it and replies with every failure the scan can prove, with the page and the code.

Request a free check

Or write to info@validiscan.com.

What the free check covers, and what it leaves out
You send
your shop’s address
Pages scanned
up to 15
You get
every failure the scan can prove, with the page and the code
On your shop
public pages only; no login, nothing bought, no forms sent
What it is not
a full audit

Write to Validiscan

For a free check, give the address of your shop and its platform.

Validiscan uses what you send to answer you. Privacy notice