Skip to content

Pre-Launch Checklist

A living checklist, not a one-off audit. Items get added as they’re discovered during development — the moment you find something that can’t ship unresolved, it goes here rather than into someone’s memory.

Meaning
🔴 Blocks launch
🟡 Should be done, won’t break the site
Done

Item Notes
🔴 Organization logo Not emitting. The header wordmark is an inline SVG snippet, so there’s no asset URL to reference. Upload the wordmark in Shopify brand settings (or the theme logo setting) and meta-tags.liquid picks it up automatically — no code change. This is the field knowledge panels most want.
🟡 Organization sameAs Not emitting. Social links live on individual footer blocks, which aren’t readable from <head>. Promote them to global theme settings, then add sameAs to the Organization node so the profiles can be claimed against the brand entity.
🔴 Product aggregateRating Blocked on Okendo. Star ratings in both AI answers and Google rich results depend on it. Wire up once the app is installed.
Sitewide Organization Emits name, url, description, contactPoint, address.
BreadcrumbList on PDP Renders on direct visits, not just collection-referred ones.
FAQPage Emits from the FAQ cluster metaobject or section blocks.
Product, WebSite + SearchAction, Article
AI crawler access GPTBot, ClaudeBot, PerplexityBot, Google-Extended all Allow: /.
Item Notes
🔴 FAQ cluster per template The FAQ section reads only from its own metaobject setting. Each template that shows FAQs needs a cluster picked in the customizer, or the section renders empty — the placeholder questions were removed.
🟡 migrelief.product_supply coverage Drives the “30-day supply” line on the PDP. Populated on MigreLief Original; confirm across every product, or variants silently fall back to the block’s static label.
🟡 migrelief.total_quantity coverage Drives per-caplet pricing and the savings badges on the pack selector. Missing values render a bare card with no per-unit price.
🟡 Accordion content metafields custom.product_information, custom.ingredients, custom.recommended_use, custom.references. Empty ones render an empty row.
Item Notes
🔴 Accordion renders empty accordion-item.liquid outputs {% content_for 'blocks' %} but never its own content setting, and nested accordion-item blocks defined in a template JSON aren’t picked up — so the wrapper renders as an empty <div>. Needs a decision: drive it from metaobjects (the accordions setting the block already supports) or from the product metafields directly.
🔴 Nested landmarks in 32 sections See below. Duplicated landmarks on nearly every section of the site — an a11y problem, not just tidiness.
🟡 Six sections never emit data-theme="dark" See below. Dark-scheme buttons and links silently don’t invert on those sections.

Shopify wraps every section’s output in its own element, controlled by the schema’s tag key and defaulting to <section>. Most sections in this theme also render a <section> as their outermost element, so the DOM ends up with <section><section> — a duplicated landmark a screen reader announces twice, and an extra box that full-bleed, overflow and sticky positioning all measure against incorrectly.

An audit of all 47 sections found 33 affected. text-image-split is fixed and sets the convention: "tag": "div" in the schema, keep the semantic <section> in the Liquid body — the body element is where the Tailwind utilities and the padding/colour custom properties already live, so nothing has to move.

Three sections have the same bug with a different element pair, and matter more because these are the page’s primary landmarks:

Section Renders Inside Shopify’s Effect
header.liquid <header> <section> Banner landmark nested in a region
footer.liquid <footer> <section> Contentinfo landmark nested in a region
main-article.liquid <article> <section> Redundant double landmark on every article

Two further clusters found by the same audit, both worth their own pass:

  • Six sections hand-roll the colour scheme (faqs, featured-banner, featured-collections, features, main-404, richtext) with inline --background / --text-color instead of the background.liquid snippet. The snippet is what emits data-theme="dark", so on those six the dark-context button and link inversion never fires. That’s a behavioural divergence, not style drift.
  • Seven customer-account sections (customers-*) render a top-level <div> with no landmark at all, and use hardcoded padding predating the current settings-driven convention.
Item Notes
🔴 Production asset build Several Alpine components exist only in source. npm run build must run before launch or the frequency selector, price display and other interactions silently do nothing.
🟡 Theme check clean Currently 53 repo-wide errors, all pre-existing. Worth burning down before launch.

The bar here is higher than compliance. WCAG 2.2 AA is the floor, not the target — nothing on this site should be arguable.

That isn’t abstract principle, it’s the audience. This product treats migraine. The people buying it are disproportionately likely to be navigating with reduced motion, high zoom, dimmed screens, or a screen reader because of the condition the product treats — photophobia, aura, and cognitive fog are symptoms, and they’re worst exactly when someone is most motivated to buy. A buy flow that only works for a well-rested user on a bright screen fails the customer at the moment they need it most.

So: no known violations at launch. Not “no blockers”, none. If something can’t be fixed before launch it gets written down here with a date, not waved through.

Automated tools catch roughly a third of real issues, so both passes below are required — a clean axe run is the starting line.

Run against home, PDP, collection, article, cart, and search. Every template type, not just the pretty ones.

  • axe DevTools — zero violations. Treat “needs review” items as work.
  • Lighthouse accessibility ≥ 95 on each template
  • Pa11y CI wired into the build, so regressions fail a PR rather than getting discovered at the next audit
  • Colour contrast — 4.5:1 body, 3:1 large text and UI components. Check the brand greens on Warmth/Sun backgrounds specifically; those pairings are the ones that tend to fail.

The part automation can’t do.

  • Keyboard only, no mouse. Tab the whole PDP buy flow: pack selector → frequency → add to cart → cart drawer → checkout. Every control reachable, in a sensible order, and operable with Enter/Space.
  • Focus is always visible. No outline: none without a replacement. Watch the pack and frequency selectors in particular — they hide the real radio with sr-only, so the visible focus ring has to come from peer-focus-visible and is easy to lose in a refactor.
  • Focus is never trapped. Quick-add modal and cart drawer: focus moves in on open, stays inside while open, returns to the trigger on close, and Escape closes.
  • Screen reader pass — VoiceOver (Safari) and NVDA (Firefox) at minimum. Does the PDP make sense read aloud, in order? Do the pack cards announce their price and savings, or just “1 Pack”?
  • Announce dynamic changes. Price and availability update without a reload; a screen reader user needs to hear that. Check aria-live on the price line and cart count.
  • Accordion and FAQ semanticsaria-expanded flips, aria-controls points at the real panel, collapsed content is genuinely hidden from the accessibility tree.
  • Zoom to 200% and 400% — no clipped content, no horizontal scroll, nothing overlapping.
  • prefers-reduced-motion — carousels, hover grow effects and transitions all respect it.
  • Images — meaningful ones have real alt text, decorative ones are alt="". No filenames as alt text.
  • Forms — every input has a real <label>, errors are announced and associated via aria-describedby, required fields aren’t indicated by colour alone.
  • Tap targets ≥ 44×44px on mobile.
  • Skip to main content link is the first focusable element.

A launch-day audit that isn’t defended decays within a sprint. Both of these should be in place before launch, not after:

  • Pa11y or axe-core in CI, failing the PR — not a report someone reads
  • Every PR touching UI states what was checked: keyboard, 375px, reduced-motion, and a11y scan. If it wasn’t checked, say so rather than leaving it implied.

The specific things that break quietly in this theme:

Pattern How it regresses
sr-only peer radios (pack + frequency selectors) The visible focus ring comes from peer-focus-visible. Drop that class in a restyle and the control becomes invisible to keyboard users while still looking fine.
Alpine x-show / x-cloak Hidden-but-present nodes stay in the accessibility tree unless genuinely removed. Prefer a Liquid {% if %} when the branch is knowable server-side.
Icon-only buttons Easy to ship without an aria-label. Cart, search, quick-add.
Colour-only state Selected pack card is green; that can’t be the only signal it’s chosen.
Auto-playing carousels Need a pause control and must respect reduced-motion.

Not yet run — do these once the above is closed out.

  • Lighthouse ≥ 95 mobile on home, PDP, collection, article
  • 375px viewport, no horizontal overflow
  • Rich Results Test on a PDP and an article
  • Staging theme is Disallow: /; production is not
  • 404 page styled and returning 404
  • Analytics firing (GA4 / GTM)
  • Checkout end to end, including a subscription line item