Les éléments select doivent avoir un nom accessible
Les listes déroulantes de taille, de couleur, de quantité, de pays ou de tri ont besoin d’un nom. Sans nom, les personnes qui utilisent un lecteur d’écran n’entendent que « zone de liste » et ne savent pas ce qu’elles choisissent, ce qui entraîne des erreurs de commande ou les empêche de finaliser leur achat.
- Identifiant de la règle
- select-name
- Source
- axe-core 4.13.0
- Impact
- Critique
- Niveau de correction
- ASSISTED
- sur Shopify, Shopware, WooCommerce et Magento
- Statut
- exécutée
Ce que fait le contrôle
Vérifier que les éléments select ont un nom accessible
La règle teste chaque <select> que les technologies d’assistance peuvent atteindre ; une liste déroulante masquée avec display: none est ignorée. Un <select> réussit avec l’une de ces sources :
- un
<label>englobant qui contient son propre texte - un
<label>avec du texte, dont leforcorrespond à l’iddu<select> - un
aria-labelavec du texte, unaria-labelledbyqui aboutit à du texte, ou untitleavec du texte role="none"ourole="presentation", mais seulement sur un<select>qui ne peut pas recevoir le focus, par exemple un<select>désactivé
Le texte des options ne compte jamais : un <label> ou un aria-labelledby dont le seul texte provient des options du <select> lui-même échoue.
Un <label for> masqué aux technologies d’assistance met le <select> en échec, sauf si une autre source le nomme malgré tout. Une étiquette masquée visuellement, mais que les lecteurs d’écran peuvent lire, est acceptée.
Quand aucune source ne nomme le <select> et que l’un de ces contrôles ne peut pas aboutir, le résultat va dans la liste « à examiner » d’axe-core, que le scanner de Validiscan ne transforme pas en constats pour l’instant. La règle ne juge pas si le nom indique au client ce qu’il choisit.
Comment corriger
Associez un <label> à chaque <select> au moyen d’attributs for et id correspondants, ou donnez-lui un aria-label ou un aria-labelledby, par exemple <label for="size">Taille</label>. Reprenez le texte de l’étiquette dans les noms d’options traduits de la boutique.
Critères de succès WCAG
- 4.1.2 Name, Role, Value, niveau A
Clauses de la norme EN 301 549
| Critère WCAG | Version 3.2.1 | Version 4.1.1 |
|---|---|---|
| 4.1.2 | 9.4.1.2 | 9.4.1.2 |
Recettes qui énumèrent cette règle
Cette règle a le niveau ASSISTED. Dans un projet, un constat de cette règle suit la voie ASSISTED, et ces recettes ne lui sont pas appliquées.
Shopify : recette label-association
Afficher l’avant et l’après (1)
sections/main-collection.liquid Modifications apportées à sections/main-collection.liquid (lignes ajoutées : 2, lignes supprimées : 2)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 64 | 64 | <div class="collection__products"> | |
| 65 | 65 | <div class="collection__toolbar"> | |
| 66 | 66 | <div class="collection__sort"> | |
| 67 | Supprimée | <label class="collection__sort-label">Sort by</label> | |
| 68 | Supprimée | <select name="sort_by" class="select__select" form="FacetFiltersForm"> | |
| 67 | Ajoutée | <label class="collection__sort-label" for="SortBy-{{ section.id }}">Sort by</label> | |
| 68 | Ajoutée | <select name="sort_by" class="select__select" form="FacetFiltersForm" id="SortBy-{{ section.id }}"> | |
| 69 | 69 | <option value="manual" selected>Featured</option> | |
| 70 | 70 | <option value="best-selling">Best selling</option> | |
| 71 | 71 | <option value="price-ascending">Price, low to high</option> |
sections/main-product.liquid Modifications apportées à sections/main-product.liquid (lignes ajoutées : 2, lignes supprimées : 2)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 94 | 94 | </div> | |
| 95 | 95 | {%- else %} | |
| 96 | 96 | <div class="product-form__input product-form__input--dropdown"> | |
| 97 | Supprimée | <p class="form__label">{{ option.name | escape }}</p> | |
| 97 | Ajoutée | <p class="form__label" id="Options-{{ section.id }}-{{ forloop.index0 }}-label">{{ option.name | escape }}</p> | |
| 98 | 98 | <div class="select"> | |
| 99 | Supprimée | <select class="select__select" name="options[{{ option.name | escape }}]" data-option-index="{{ option_index }}"> | |
| 99 | Ajoutée | <select class="select__select" name="options[{{ option.name | escape }}]" data-option-index="{{ option_index }}" aria-labelledby="Options-{{ section.id }}-{{ forloop.index0 }}-label"> | |
| 100 | 100 | {%- for value in option.values %} | |
| 101 | 101 | <option value="{{ value | escape }}"{% if value == option.selected_value %} selected{% endif %}>{{ value | escape }}</option> | |
| 102 | 102 | {%- endfor %} |
Shopware : recette label-association
Afficher l’avant et l’après (1)
Resources/views/storefront/page/product-detail/configurator.html.twig Modifications apportées à Resources/views/storefront/page/product-detail/configurator.html.twig (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 13 | 13 | {% for group in product.configurator %} | |
| 14 | 14 | {% if group.display == 'select' %} | |
| 15 | 15 | <div class="product-detail-configurator-group"> | |
| 16 | Supprimée | <div class="product-detail-configurator-group-title">{{ group.name }}</div> | |
| 16 | Ajoutée | <label class="product-detail-configurator-group-title" for="configurator-{{ group.id }}">{{ group.name }}</label> | |
| 17 | 17 | <select class="form-select product-detail-configurator-select-input" | |
| 18 | 18 | id="configurator-{{ group.id }}" | |
| 19 | 19 | name="{{ group.id }}"{% if group.price|default(false) %} |
WooCommerce : recette label-association
Afficher l’avant et l’après (1)
woocommerce/cart/cart.php Modifications apportées à woocommerce/cart/cart.php (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 62 | 62 | <tr> | |
| 63 | 63 | <td colspan="6" class="actions"> | |
| 64 | 64 | <div class="coupon"> | |
| 65 | Supprimée | <label class="screen-reader-text"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> | |
| 65 | Ajoutée | <label class="screen-reader-text" for="coupon_code"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> | |
| 66 | 66 | <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="<?php esc_attr_e( 'Coupon code', 'woocommerce' ); ?>"> | |
| 67 | 67 | <button type="submit" class="button" name="apply_coupon" value="<?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?>"><?php esc_html_e( 'Apply coupon', 'woocommerce' ); ?></button> | |
| 68 | 68 | </div> |
Magento : recette label-association
Afficher l’avant et l’après (1)
app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/list/toolbar.phtml Modifications apportées à app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/list/toolbar.phtml (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 12 | 12 | <div class="toolbar-sorter sorter"> | |
| 13 | 13 | <!-- VALIDISCAN-SEEDED select-name + vs-forms-ecommerce: the "Sort By" text is a span, not a label for the select --> | |
| 14 | 14 | <?php /* Fixed variant: <label class="sorter-label" for="sorter">Sort By</label>. */ ?> | |
| 15 | Supprimée | <span class="sorter-label"><?= $escaper->escapeHtml(__('Sort By')) ?></span> | |
| 15 | Ajoutée | <label class="sorter-label" for="sorter"><?= $escaper->escapeHtml(__('Sort By')) ?></label> | |
| 16 | 16 | <select id="sorter" data-role="sorter" class="sorter-options"> | |
| 17 | 17 | <?php foreach ($block->getAvailableOrders() as $key => $order): ?> | |
| 18 | 18 | <option value="<?= $escaper->escapeHtmlAttr($key) ?>"<?= $block->isOrderCurrent($key) ? ' selected' : '' ?>><?= $escaper->escapeHtml(__($order)) ?></option> |
Commencez par une vérification gratuite de votre boutique.
Envoyez l’adresse de votre boutique. Validiscan la scanne et vous envoie chaque échec que le scan peut prouver, avec sa page et son code.
Demander une vérification gratuiteOu écrivez à info@validiscan.com.
Ce que couvre la vérification gratuite, et ce qu’elle laisse de côté- Vous envoyez
- l’adresse de votre boutique
- Pages scannées
- jusqu’à 15
- Vous recevez
- chaque échec que le scan peut prouver, avec la page et le code
- Sur votre boutique
- pages publiques uniquement ; aucune connexion, aucun achat, aucun formulaire envoyé
- Ce qu’elle n’est pas
- un audit complet