Accessibility
Overview
SCAYLE Storefront aims to make shopping experiences more inclusive by addressing accessibility considerations. This guide recounts our journey, highlighting the steps we’ve taken to integrate accessibility improvements into a Storefront application.
Why Accessibility Matters to Us
Accessibility ensures that our platform can be used by everyone, including individuals with disabilities. We’ve improved usability for those with vision, hearing, cognitive, and motor impairments. These guidelines focus on key areas such as color contrast, navigation, and alternative text, offering a pathway to create a more inclusive digital experience.
Our Approach to Accessibility
Starting with an Audit
We started by identifying areas for improvement through an accessibility audit. We utilized tools like Wave, Axe, and ARC Toolkit to uncover issues such as:
- Low contrast text
- Missing ARIA labels
- Structural inconsistencies
This audit gave us a clear starting point to address accessibility gaps.
Implementing Quick Wins
Language Settings
Adding the <lang>
attribute to define the content language, ensuring accurate pronunciation by screen readers. This tag is dynamically set based on the shop’s configuration to match the user’s language settings.
// Dynamic 'lang' value is set in the following
// two layouts by default:
// - 'layouts/default.vue'
// - 'layouts/simple.vue'
// (...)
import { useHead } from '@unhead/vue'
import { useCurrentShop } from '#storefront/composables'
// (...)
// Meta tags
useHead({
// (...)
htmlAttrs: () => ({
lang: new Intl.Locale(currentShop.value.locale).language,
})
// (...)
})
// (...)
Text Alternatives
Ensuring all product images had meaningful alt
text or empty alt
attributes for decorative visuals.
- Meaningful Images: descriptive
alt
text for key visuals (e.g., “Red sweater with buttons”).
// See 'composables/useProductBaseInfo.ts' as used
// in e.g. 'components/product/card/SFProductCard.vue'.
// (...)
// Generates a string like
// "ADIDAS ORIGINALS, Dress, Black"
const alt = computed(() => {
return t('product_image.alt', {
productName: name.value,
colors: formatColors(
getAttributeValueTuples(product.value?.attributes, 'color'),
),
brand: brand.value,
})
})
// (...)
<!-- See components/product/card/imageSlider/SFProductCardImageSlider.vue -->
<template>
<!-- (...) -->
<!--
The property 'alt' is generated by the previously showed 'useProductBaseInfo' composable.
The ':alt' tag / binding is supplemented with the product image counts to generate
a string like "ADIDAS ORIGINALS, Dress, Black, Image 1 of 4".
-->
<SFProductImage
v-if="item"
:image="item"
:alt="
$t('product_image.alt_with_image_index', {
alt,
index: imageIndex + 1,
total: images.length,
})
"
:image-loading="getImageLoading(imageIndex)"
:preload="shouldPreload(imageIndex)"
sizes="xs:50vw sm:50vw md:40vw lg:33vw xl:320px"
class="absolute inset-0"
/>
<!-- (...) -->
</template>
- Decorative Images: empty
alt
attributes (alt=""
) for decorative visuals to avoid clutter. - Functional Images:
alt
text that describes the action (e.g., “Open user profile”).
Color Contrast
Adjusting text and interactive element contrast to meet the 4.5:1 ratio, with enhanced focus indicators for keyboard navigation.
.png)
Double Outline On A Colorful Background
<!-- See 'components/layout/headers/SFShopSwitcher.vue' -->
<template>
<!-- (...) -->
<!--
Relevant for the first outline: ':focus-visible';
Relevant for "double" focus outline: '-outline-offset-5' & 'focus-visible:shadow-inner-solid'
See https://tailwindcss.com/docs/hover-focus-and-other-states#hover-focus-and-active
-->
<SFButton
ref="button"
variant="raw"
:listbox-button-aria-id="listboxButtonAriaId"
:aria-label="
$t('shop_selector.aria_label', {
selectedCountry,
selectedLanguage,
})
"
aria-haspopup="true"
:aria-expanded="isOpen"
class="h-full gap-1.5 px-2 !text-gray-600 -outline-offset-5 hover:bg-indigo-200/10 focus-visible:shadow-inner-solid lg:!text-white"
data-testid="language-listbox"
@click="toggle"
>
<!-- (...) -->
</SFButton>
<!-- (...) -->
</template>
Improving Navigation and Interaction
Page Structure
We implemented semantic HTML with landmarks like <nav>
and <main>
to improve navigation. Skip links were added to enable users to bypass repetitive content easily.
.png)
Skip Links Displayed via Keyboard Navigation
Page Titles
We standardized page titles to reflect content clearly:
- PLP:
{category_name} - {shop_name}
(e.g., "Accessories - SCAYLE") - PDP:
{product_name} - {shop_name}
(e.g., "Red Bag - SCAYLE")
The {shop_name}
is dynamically retrieved from the platform’s configuration file for consistency.
Links and Buttons
We clarified the use of <a>
and <button>
elements:
<a>
tags navigate users to new pages (e.g., account, wishlist, and basket icons in the mobile navigation).<button>
tags trigger actions (e.g., hamburger menu).
.png)
Button and Link Elements in the Navigation
Further Improvements
Headings
We’re ensuring a logical structure by using only one <h1>
per page and phasing out non-semantic replacements like <div>
or <span>
.
.png)
Headings Structure if the Basket Page
Lists
Proper list elements are being introduced for navigation menus and dropdowns to improve compatibility with assistive technologies.
.png)
Using Lists for Navigation and Dropdowns
Keyboard Navigation
We’re enhancing keyboard interactions with clear focus states and intuitive controls for components like carousels, flyouts and pop-ups.
.png)
Flyout Link Focus State
Pop-ups
Accessibility features include focus traps, visible close buttons, and support for the "Escape" key.
Forms
We are updating forms with clearly labeled input fields and actionable error messages to guide users effectively through corrective actions.
.png)
Login Form Errors
Labels & Titles
We’re ensuring concise, descriptive labels and titles for all elements. We are also implementing aria-label
and aria-labelledby
for elements requiring additional context beyond visual text. Screen reader testing is helping us identify and close gaps in label clarity.
Testing Strategy
To maintain high accessibility standards, we combined automated and manual testing:
- Automated Audits: Tools like Axe and Lighthouse helped us catch high-level issues.
- Manual Checks: We tested with screen readers (e.g., VoiceOver, NVDA) and verified keyboard navigation on critical user journeys.
Final Checks and Continuous Improvement
Our work doesn’t stop here. While we’ve addressed essential areas, we continue to refine our approach by:
- Ensuring accessible pop-ups with focus traps and keyboard support.
- Improving labels and titles for screen readers.
- Adding more detailed multimedia descriptions and refining complex interactions.
- Expanding our accessibility testing toolkit.
Resources
Recommended Tools
Automated Testing
- Axe: A browser extension that scans pages and highlights accessibility issues, allowing you to prioritize areas that need improvement.
- Lighthouse: Built into Chrome DevTools, Lighthouse evaluates accessibility, performance, and SEO, providing a report with actionable suggestions.
- Wave: Wave provides insights into issues like color contrast, ARIA labels, and HTML structure, offering quick ways to improve accessibility.
- ARC Toolkit: A powerful tool for in-depth accessibility audits, ARC Toolkit provides detailed analysis and recommendations, particularly useful for evaluating complex HTML structures and ARIA roles.
Manual Testing Tools
- Screen Readers: Test with VoiceOver (Mac) or NVDA (Windows) to understand how screen readers interpret your site and ensure content is accessible to visually impaired users.
- Color & Contrast Checkers: Tools like WebAIM’s Contrast Checker help verify that text is readable against its background, meeting WCAG contrast standards.
DevTools for Accessibility
- Chrome DevTools: The “Accessibility” tab allows you to simulate color blindness, check keyboard accessibility, and view the Accessibility Tree, which shows how elements are exposed to assistive technologies like screen readers.
- Accessibility Tree: This feature in DevTools displays the hierarchy of accessible elements on the page, helping you assess how screen readers will interact with each element.
Helpful Links
\