Northwind StudioOctober 24, 2026

Accessibility health check: harbor-goods.example

Prepared for Harbor Goods (fictional demo store) · 4 key pages tested with automated WCAG 2.2 AA checks and keyboard testing.

26
At risk
Health score / 100
10
issue types found
83
affected elements
9
critical or serious

Automated testing finds a meaningful share of accessibility barriers, but not all of them. This report is a prioritised starting point for remediation, not a legal opinion or a certification of conformance.

Pages tested

Issues, highest impact first

1

Images must have alternative text

Critical 9 instances on home, collection, cart WCAG 1.1.1

Why it matters

Screen-reader users hear nothing (or a file name) for these images, so products and banners are invisible to them.

How to fix

Give every meaningful image alt text. In Shopify themes, render alt from the image object with a sensible fallback.

<img src="{{ image | image_url: width: 800 }}" alt="{{ image.alt | default: product.title | escape }}">
Example element
<img src="data:image/svg+xml,%...">
Screenshot with the affected element outlined in red
Affected element outlined in red
2

Buttons must have discernible text

Critical 4 instances on home, collection, product, cart WCAG 4.1.2

Why it matters

Buttons with no name (e.g. icon-only close, menu or quantity buttons) are announced as just "button".

How to fix

Add an aria-label describing the action, or visually hidden text inside the button.

<button type="button" aria-label="Close menu">
  <svg aria-hidden="true" focusable="false">…</svg>
</button>
Example element
<button><svg width="16" height="16" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path d="M6 6l12 12M18 6 6 18"></path></svg></button>
Screenshot with the affected element outlined in red
Affected element outlined in red
3

Select element must have an accessible name

Critical 2 instances on collection, product WCAG 4.1.2

Why it matters

Dropdowns (variant pickers, sort-by) without labels are announced without context.

How to fix

Add a <label> or aria-label to every <select>.

<label for="SortBy">Sort by</label>
<select id="SortBy" name="sort_by">…</select>
Example element
<select><option>Featured</option><option>Price, low to high</option><option>Price, high to low</option></select>
Screenshot with the affected element outlined in red
Affected element outlined in red
4

Form elements must have labels

Critical 2 instances on product, cart WCAG 4.1.2

Why it matters

Form fields without labels (newsletter, search, quantity) leave screen-reader users guessing what to type.

How to fix

Associate a <label> with each input; it can be visually hidden if the design requires.

<label for="NewsletterEmail" class="visually-hidden">Email address</label>
<input id="NewsletterEmail" type="email" name="contact[email]" autocomplete="email">
Example element
<input value="1" style="width:40px;text-align:center">
Screenshot with the affected element outlined in red
Affected element outlined in red
5

Links must have discernible text

Serious 26 instances on home, collection, product, cart WCAG 2.4.4, 4.1.2

Why it matters

Links with no accessible name are announced as just "link", so users cannot tell where they go (common on icon-only social/cart links).

How to fix

Add visible text or an aria-label to icon-only links, and mark decorative SVGs aria-hidden.

<a href="{{ routes.cart_url }}" aria-label="Cart ({{ cart.item_count }} items)">
  {% render 'icon-cart' %}
</a>
Example element
<a href="/search/"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"></circle><path d="m20 20-4-4"></path></svg></a>
Screenshot with the affected element outlined in red
Affected element outlined in red
6

Elements must meet minimum color contrast ratio thresholds

Serious 24 instances on home, collection, product, cart WCAG 1.4.3

Why it matters

Low-contrast text is hard or impossible to read for people with low vision, and on phones in sunlight.

How to fix

Darken the text (or lighten the background) to reach at least 4.5:1 for body text and 3:1 for large text. Suggested colours are computed below.

/* #b9b2a3 on #f3efe6 is 1.83:1, needs 4.5:1 */
/* use #6f6b62 (4.64:1) */

/* #999999 on #ffffff is 2.84:1, needs 4.5:1 */
/* use #747474 (4.66:1) */

/* #ffffff on #e8b4a8 is 1.82:1, needs 4.5:1 */
/* use #4c4c4c (4.68:1) */

/* #777777 on #222222 is 3.55:1, needs 4.5:1 */
/* use #8a8a8a (4.61:1) */
Example element
<div class="announce">Free shipping on orders over $75 <button><svg width="16" height="16" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path d="M6 6l12 12M18 6 6 18"></path></svg></button></div>
Screenshot with the affected element outlined in red
Affected element outlined in red
7

7 of 7 keyboard stops have no visible focus indicator

Serious 7 instances on home WCAG 2.4.7

Why it matters

Keyboard users cannot see where they are on the page when focus has no visible indicator.

How to fix

Add a clear :focus-visible style (and never remove outlines without a replacement).

:focus-visible {
  outline: 3px solid #1a5fff;
  outline-offset: 2px;
}
Example element
8

<html> element must have a lang attribute

Serious 4 instances on home, collection, product, cart WCAG 3.1.1

Why it matters

Without a page language, screen readers may read the store in the wrong accent or language.

How to fix

Set the lang attribute on <html> in layout/theme.liquid.

<html lang="{{ request.locale.iso_code }}">
Example element
<html>
Screenshot with the affected element outlined in red
Affected element outlined in red
9

Frames must have an accessible name

Serious 1 instance on product WCAG 4.1.2

Why it matters

Embedded frames (videos, reviews widgets, chat) without titles are unidentifiable.

How to fix

Add a descriptive title attribute to each iframe.

<iframe src="…" title="Product video: {{ product.title | escape }}"></iframe>
Example element
<iframe src="about:blank" style="width:100%;height:60px;border:0;margin-top:20px"></iframe>
Screenshot with the affected element outlined in red
Affected element outlined in red
10

Zooming and scaling must not be disabled

Moderate 4 instances on home, collection, product, cart WCAG 1.4.4

Why it matters

Disabling zoom prevents low-vision users from enlarging the page.

How to fix

Remove maximum-scale=1 and user-scalable=no from the viewport meta tag.

<meta name="viewport" content="width=device-width,initial-scale=1">
Example element
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

What ongoing monitoring adds