Bug description
ui/Switch.vue renders a role="switch" button whose only child is a decorative SwitchThumb. It declares no aria-label or aria-labelledby prop, so unless a call site passes one the control has no accessible name at all. A screen reader announces "switch, on" with no indication of what is on.
ToggleFieldtype does pass :aria-label="__(config.display)" and is fine. Thirteen other call sites do not:
The entry publish toggle is the notable one: it is arguably the single most important control in the CP.
axe-core reports button-name (critical) on 39 nodes across 6 screens.
Source: https://github.com/statamic/cms/blob/v6.31.0/resources/js/components/ui/Switch.vue
WCAG 2.1 SC 4.1.2 Name, Role, Value (Level A).
How to reproduce
composer create-project statamic/statamic
- Open any entry for editing
- Inspect the published-state toggle in the sidebar
Expected: an aria-label or aria-labelledby. Actual: <button role="switch" aria-checked="true"> with no name.
Same on /cp/sites (site enabled) and /cp/roles/create (super user).
Suggested fix
Add a label / ariaLabel prop to ui/Switch.vue and pass a real name at each of the thirteen call sites.
Two of them already have the right string sitting in a v-tooltip (__('Included in output') / __('Hidden from output') in the Bard and Replicator sets); it just needs to reach aria-label too.
Making the prop required would prevent the class of bug from coming back.
Environment
Environment
Laravel Version: 13.30.1
PHP Version: 8.4.23
Composer Version: 2.10.2
Environment: local
Debug Mode: ENABLED
Maintenance Mode: OFF
Timezone: UTC
Locale: en
Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED
Drivers
Broadcasting: log
Cache: file
Database: sqlite
Logs: stack / single
Mail: log
Queue: sync
Session: file
Storage
public/storage: NOT LINKED
Statamic
Addons: 0
License Key: Not set
Sites: 1
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 6.31.0 PRO
Installation
Fresh statamic/statamic site via CLI
Additional details
Found during a WCAG 2.1 AA audit of a vanilla composer create-project statamic/statamic install with no addons and no custom code. Tested with axe-core 4.x on Chromium 153 at 1440x1000, plus manual keyboard traversal. Source references point at v6.31.0.
Bug description
ui/Switch.vuerenders arole="switch"button whose only child is a decorativeSwitchThumb. It declares noaria-labeloraria-labelledbyprop, so unless a call site passes one the control has no accessible name at all. A screen reader announces "switch, on" with no indication of what is on.ToggleFieldtypedoes pass:aria-label="__(config.display)"and is fine. Thirteen other call sites do not:The entry publish toggle is the notable one: it is arguably the single most important control in the CP.
axe-core reports
button-name(critical) on 39 nodes across 6 screens.Source: https://github.com/statamic/cms/blob/v6.31.0/resources/js/components/ui/Switch.vue
WCAG 2.1 SC 4.1.2 Name, Role, Value (Level A).
How to reproduce
composer create-project statamic/statamicExpected: an
aria-labeloraria-labelledby. Actual:<button role="switch" aria-checked="true">with no name.Same on
/cp/sites(site enabled) and/cp/roles/create(super user).Suggested fix
Add a
label/ariaLabelprop toui/Switch.vueand pass a real name at each of the thirteen call sites.Two of them already have the right string sitting in a
v-tooltip(__('Included in output')/__('Hidden from output')in the Bard and Replicator sets); it just needs to reacharia-labeltoo.Making the prop required would prevent the class of bug from coming back.
Environment
Installation
Fresh statamic/statamic site via CLI
Additional details
Found during a WCAG 2.1 AA audit of a vanilla
composer create-project statamic/statamicinstall with no addons and no custom code. Tested with axe-core 4.x on Chromium 153 at 1440x1000, plus manual keyboard traversal. Source references point atv6.31.0.