Skip to content

Uisce Preset Support Pack

Diagnostic and troubleshooting reference for the Uisce services preset — booking CTA, portfolio, service packages, and niche metafields.


FAQ

Q: The booking form submits but nothing happens.

A: The form requires a valid form_action_url endpoint. Check:

  1. Is form_action_url set in the Booking CTA section settings? An empty URL causes the form to POST back to the current page with no handler.
  2. Is your endpoint returning HTTP 200? Check the browser Network tab after form submission.
  3. What does the endpoint respond with? The form is a native full-page POST — the browser navigates to the endpoint and shows its response directly (CORS does not apply to this kind of submission, and the theme renders no success state of its own). Configure the endpoint (Formspree, Netlify Forms, etc.) to redirect back to a page on your store or serve its own confirmation page.

Q: The deposit shows a dash ("—") or a wrong amount.

A: The deposit is read from the selected service block's deposit_amount setting — an absolute amount in your store currency (a number setting, not a percentage). Liquid formats it through the money filter into a data-deposit-label attribute on each <option>, and the summary rail prefers that formatted label. Check:

  1. A dash ("—") means no service is selected yet — the summary shows a placeholder until the customer picks a service.
  2. A bare, unformatted number (e.g. "0") means the selected service block's deposit_amount is blank or 0 — with no formatted label to show, the JS falls back to the raw data-deposit value. Set deposit_amount on the block.
  3. A wrong amount usually means the value was entered in minor units: deposit_amount is in whole store-currency units (enter 40 for a $40.00 deposit, not 4000).

A: The submit button is gated on exactly one thing: the consent checkbox. niche-uisce.js enables the button when the checkbox is checked and disables it when unchecked; required fields are then enforced by native HTML5 validation at submit time. If checking the box does not enable the button:

  1. Check the browser console for JavaScript errors — the booking module loads as a dynamic import, and an error during init leaves the button in its initial disabled state.
  2. Check for theme-code edits: the JS looks for input[type="checkbox"][name="consent"] inside form[data-booking-cta-form]. Renaming either attribute breaks the wiring.

Shopify's Customer Privacy API does not participate in this gate. It only decides whether an analytics event fires alongside the POST — no cookie-banner or tracking-consent state can disable the submit button or block the form.

Q: Portfolio before/after images are not showing.

A: Older theme versions had a bug where the portfolio section emitted escaped HTML text instead of rendered images. This is resolved in current theme versions. Verify you are on a theme version that includes the fix by checking the assets/portfolio.css file date in the theme files list.

Q: Category filter in the portfolio section shows duplicate categories.

A: The portfolio filter deduplicates categories by handle — case- and space-insensitive. "Residential", "residential", and " Residential " all collapse into a single tab, and the first spelling a merchant entered wins as the tab label. If you still see two tabs:

  1. The category names differ beyond case/spacing — check for typos ("Residental" vs "Residential") or singular/plural variants ("Kitchen" vs "Kitchens"), which are genuinely distinct categories.
  2. Edit the portfolio blocks to use one canonical spelling per category.

Q: Service packages section is showing on non-Uisce preset pages.

A: The service-packages section has no case settings.preset guard in the Liquid template. If you are using a shared theme across multiple presets, the section may appear on non-Uisce preset pages visually. To hide it on non-Uisce pages:

  • Either add the section only to Uisce-specific page templates
  • disabled_on cannot help here — it restricts a section by template or section group, not by preset

Decision Tree: "Why is my booking form not working?"

Symptom: Booking form does not submit

  -> Is form_action_url set?
    -> No: Set it in Booking CTA section settings → Form action URL
    -> Yes: Continue

  -> Is the submit button enabled?
    -> No: The consent checkbox is the only gate — check it. If the button stays disabled,
       check the JS console for errors (the booking module failed to initialize)
    -> Yes: Continue

  -> Does the browser Network tab show a request after clicking Submit?
    -> No: A required field is failing native validation — look for the browser's field hint
    -> Yes: Continue

  -> What HTTP status does the endpoint return?
    -> 200: The browser is showing the endpoint's response — the theme renders no success state.
       Configure the endpoint to redirect back to your store or serve a confirmation page
    -> 4xx/5xx: Check the endpoint accepts a plain form-encoded POST from a browser navigation

  -> Still stuck?
    -> Check niche-uisce.js version; may be serving pre-Phase-06.10-01 cached file

Validator Interpretation

"Lighthouse: Booking CTA page has Accessibility score < 0.9"

Most common cause on Uisce: form input labels not associated with inputs (missing for/id pairs). The theme ships correct associations. If you have added custom HTML blocks near the form, check that any custom form elements use <label for="input-id"> pairings.

"axe: Form element doesn't have an accessible name"

Check whether the booking form's service <select> element has a <label> associated via for/id. This is shipped correctly in the theme; if you see this error, check for a theme code edit that may have broken the label association.

"Theme check: form_action_url setting value is empty"

This is expected in development before you configure your form endpoint. It is not a theme-check offense — it is a schema type: url setting with an empty default. Set the value in the theme editor before deploying to production.


Console Diagnostic Snippet

Paste into DevTools Console on any Uisce page to get a structured diagnostic report:

js
(function uisceDiagnostic() {
  'use strict';
  const r = {
    preset: document.body.className.match(/preset-([a-z]+)/)?.[1] ?? 'unknown',
    bookingCTA: {
      present: !!document.querySelector('niche-renderer[data-preset="uisce"]'),
      formAction: document.querySelector('form[data-booking-cta-form]')?.action ?? 'NOT SET',
      consentChecked: document.querySelector('input[name="consent"]')?.checked ?? false,
      customerPrivacyLoaded: typeof window?.Shopify?.customerPrivacy !== 'undefined',
      analyticsAllowed: (function () {
        try {
          return window.Shopify.customerPrivacy.analyticsProcessingAllowed();
        } catch {
          return 'API_NOT_LOADED';
        }
      })(),
    },
    portfolio: {
      present: !!document.querySelector('.portfolio'),
      itemCount: document.querySelectorAll('.portfolio__card').length,
      filterButtons: document.querySelectorAll('[data-portfolio-filter]').length,
    },
    servicePackages: {
      present: !!document.querySelector('.service-packages'),
      tierCount: document.querySelectorAll('.service-packages__card').length,
    },
    nicheMetafieldNamespace: document.querySelector('[data-niche-namespace]')?.dataset?.nicheNamespace ?? 'not found',
    presetCSS: !!document.querySelector('link[href*="preset-uisce"]'),
  };
  console.group('%cUisce Diagnostic Report', 'color:#006989;font-weight:bold;font-size:14px');
  console.table(r.bookingCTA);
  console.log('Portfolio:', r.portfolio);
  console.log('Service Packages:', r.servicePackages);
  console.log('Preset CSS loaded:', r.presetCSS);
  console.groupEnd();
  return r;
})();

Expected output when working correctly:

  • formAction: your configured endpoint URL (not empty, not the current page)
  • consentChecked: false initially, true after customer checks the box
  • customerPrivacyLoaded: true on production stores (informational — analytics only, never gates the submit button)
  • presetCSS: true

Accessibility Diagnostic

Running the axe check against the booking page

bash
# Run the axe CLI (dev only — package name is @axe-core/cli)
npx @axe-core/cli "https://your-store.myshopify.com/pages/book-a-service"

Or use Chrome DevTools → Accessibility → Run axe. Expected: 0 critical violations.

Booking form aria requirements

For the booking form to pass WCAG 2.1 AA:

  • Every <input>, <select>, <textarea> must have an associated <label> (via for/id)
  • The consent checkbox must have a visible label — not just an aria-label
  • The submit button must have accessible text (not just an icon)
  • Error messages must be associated with their fields via aria-describedby
  • The live error summary carries role="alert" alongside an explicit aria-live="polite", so the consent error is announced politely rather than interrupting
  1. In Chrome, open an incognito window and navigate to your booking page.
  2. Check the consent checkbox and verify the submit button becomes enabled. The checkbox is the only gate on the button — cookie-banner / tracking-consent state has no effect on it.
  3. Uncheck the box and verify the button disables again.
  4. Fill the required fields and submit: the browser navigates to your form endpoint's response. Verify the endpoint's redirect or confirmation page behaves as configured — the theme itself renders no success state.

Localization Notes

The GDPR consent checkbox copy is controlled by the sections.booking_cta.consent.body_html locale key. The theme ships this key in all 50 locales. If you need jurisdiction-specific consent language (e.g., PIPEDA for Canada, LGPD for Brazil), override the locale key via the Shopify Translation app for the relevant locale.

Service name localization

Service block names in the booking form's select element are merchant-entered text in theme settings — they are not localized via the locale system. If you operate a multilingual store, create separate theme presets or use the translation app to translate service names per locale.


Curl Cheat-Sheet

bash
# Verify Service + Offer JSON-LD on a service product
curl -s "https://your-store.myshopify.com/products/standard-clean" \
  | grep -o '"@type": "Service"[^<]*' | head -5

# Check the booking form (native POST) is present on the booking page
curl -s "https://your-store.myshopify.com/pages/book-a-service" \
  | grep -c 'data-booking-cta-form'

# Verify preset-uisce.css is linked in the page head
curl -s "https://your-store.myshopify.com" \
  | grep 'preset-uisce'

# Check booking-cta section is present on the book page
curl -s "https://your-store.myshopify.com/pages/book-a-service" \
  | grep -c 'booking-cta'

Deployment Checklist

Before going live with the Uisce preset:

  • [ ] settings.preset set to uisce in Theme settings
  • [ ] form_action_url set in Booking CTA section settings (not blank)
  • [ ] Form endpoint response verified — endpoint redirects back to the store or serves its own confirmation page (the theme renders no success state)
  • [ ] At least 2 service blocks in Booking CTA with service_name, service_handle, and deposit_amount set
  • [ ] Page book-a-service created and assigned page.book template
  • [ ] Portfolio section has at least 2 case-study blocks with images
  • [ ] Page portfolio created and assigned page.portfolio template
  • [ ] Service packages has at least 2 Service blocks with inclusions
  • [ ] Booking CTA consent checkbox present and functional (test consent flow above)
  • [ ] Service + Offer JSON-LD appears on service product pages (curl check)
  • [ ] Portfolio category filter shows one tab per category (deduplication is case- and space-insensitive; the first spelling entered wins as the tab label)
  • [ ] preset-uisce.css linked in page head
  • [ ] Header menu includes "Book a Service" and "Portfolio" links
  • [ ] GDPR consent text is present and uses booking-specific purpose language
  • [ ] Deposit calculation shows correct values for each service (test in browser)

Support pack last updated: 2026-05-03 (Phase 06.10 closeout)

Built for the Shopify Theme Store.