Phase 7:
JavaScript Interactions

Custom Web Components on PDP — Tabs, Variant Descriptions & Sticky Add-to-Cart

WinSport Theme · Custom Elements · Pub/Sub Events · IntersectionObserver

Why Web Components?

3
Components
0
Dependencies
5
New Files
100%
Dawn-native

Dawn’s architecture uses Custom Elements (Web Components) with a pub/sub event system for decoupled communication. Phase 7 adds three interactive components that follow this exact pattern — no jQuery, no frameworks, no global side effects. Each component self-registers, manages its own lifecycle, and conditionally loads only when its block exists.

Three Components

<product-tabs>

Tabbed Content

Multiple content panels behind tab headers. Full ARIA support: role="tablist/tab/tabpanel", aria-selected, keyboard navigation with Arrow/Home/End keys.

<variant-description>

Conditional Text

Listens to variantChange via pub/sub. Shows variant-specific text (e.g. "Limited edition color") and hides others. Falls back to default message.

<sticky-atc>

Sticky Add to Cart

IntersectionObserver on the main ATC button. When it scrolls out of view, a fixed bottom bar slides up with product name, price, and buy button.

Product Tabs

Live Screenshot Product Tabs — Details and Shipping tabs on PDP
  • ARIA pattern: role="tablist" container, role="tab" buttons, role="tabpanel" content areas
  • aria-selected toggles with active tab; inactive tabs get tabindex="-1"
  • Keyboard: ArrowLeft/Right cycles tabs, Home/End jump to first/last
  • Focus management: activateTab() calls focus() on new tab button
  • Up to 3 tabs configurable in theme customizer with richtext content
  • CSS fade-in animation with prefers-reduced-motion respect

Variant Description & Sticky ATC

Tabs + Variant Text Product Tabs with variant description on PDP
  • Subscribes to PUB_SUB_EVENTS.variantChange
  • Matches [data-variant-id] to selected variant
  • Falls back to [data-variant-default] when no match
  • Unsubscribes in disconnectedCallback
Sticky Add-to-Cart Bar Sticky Add to Cart bar at bottom of page
  • IntersectionObserver watches main ATC button
  • Toggles .is-visible class on scroll
  • Syncs price/availability via variantChange
  • Delegates submit to main product-form

Code Highlights

// variant-description.js
connectedCallback() {
  this.onVariantChangeUnsubscriber =
    subscribe(
      PUB_SUB_EVENTS.variantChange,
      this.handleVariantChange.bind(this)
    );
}

handleVariantChange({ data: { variant } }) {
  const match = this.querySelector(
    `[data-variant-id="${variant.id}"]`
  );
  // show match, hide others
}

disconnectedCallback() {
  this.onVariantChangeUnsubscriber();
}
// sticky-atc.js
connectedCallback() {
  this.observer = new IntersectionObserver(
    this.handleIntersect.bind(this),
    { threshold: 0 }
  );
  this.observer.observe(
    document.querySelector('[data-atc-trigger]')
  );
}

handleIntersect(entries) {
  entries.forEach((entry) => {
    this.classList.toggle(
      'is-visible',
      !entry.isIntersecting
    );
  });
}

Data Flow

Dawn Pub/Sub pubsub.js
constants.js
variantChange Published by
product-info.js
Subscribers variant-description
sticky-atc
IntersectionObserver [data-atc-trigger]
on buy_buttons
<sticky-atc> .is-visible toggle
CSS transition
product-form Delegated submit
requestSubmit()
Liquid Blocks 3 new types in
main-product schema
Conditional Load JS/CSS only when
block is added
Theme Customizer Add/remove/reorder
in admin UI

Key Takeaways

  • Dawn-native architecture — Custom Elements + pub/sub, same patterns as product-info, product-form, cart-drawer
  • Zero dependencies — vanilla JS only, no frameworks, no jQuery, no bundler needed
  • Full accessibility — ARIA tablist pattern, keyboard navigation, focus management, prefers-reduced-motion
  • Conditional loading — JS/CSS files only load when their block is added in the customizer — zero cost otherwise
  • Lifecycle cleanup — all event listeners and observers disconnected in disconnectedCallback
  • Decoupled via events — components don’t reference each other, communicate only through pub/sub

WinSport Theme · Phase 7 Complete · Dawn v15.4.1 · Shopify 2.0