Shopify 2.0 Portfolio

WinSport
Theme

End-to-end Shopify theme development — from Dawn base to production-ready store

10 Phases · Custom Design · Zero Dependencies

Project Overview

The Numbers

10
Phases
6
Pull Requests
0
Dependencies
95+
Liquid Files

Structure → Design → Sections → Metafields → App Data → VAT Pricing → JS Interactions → Performance → Git → Docs

Tech Stack

Built With

Platform

Shopify 2.0

Online Store 2.0 architecture with JSON templates and section-everywhere support

Templating

Liquid

Shopify's templating language with filters, conditional rendering, and metafield access

JavaScript

Vanilla JS

Web Components, custom elements, zero jQuery — event delegation and module pattern

CSS

Mobile-First

Responsive design, CSS custom properties, no preprocessors

Base Theme

Dawn v15.4.1

Shopify's reference theme — fully customized and extended

Tooling

Shopify CLI

Local development, theme push/pull, Lighthouse audits

Phase 2

Before: Dawn Default

Dawn default homepage

Stock Dawn theme — generic, no brand identity

Phase 2

After: WinSport Design

WinSport PDP design

Custom luxury sports aesthetic — Cormorant + Work Sans, beige & navy palette

Phase 2

Design System

Cormorant Garamond
Work Sans — UI & Body
#F5F0EB
#E8DFD6
#3A3A4A
#1a1a1a
  • Pixel-accurate Figma implementation
  • Mobile-first responsive approach
  • No page builders — all code
  • CSS custom properties for theming
  • Consistent spacing & typography scale
Phase 3

Dynamic Blocks

Admin Theme Customizer
Admin block reordering
  • Custom sections with {% schema %} blocks
  • Drag-and-drop reordering in admin
  • JSON templates for section-everywhere
  • Specs showcase section on PDP
  • Product Features with dynamic content
Phase 4

Product Metafields

Conditional Rendering on PDP
PDP with metafields
  • care_instructions — multi-line text
  • difficulty_rating — numeric scale
  • is_new_arrival — boolean badge
  • Show only if filled — zero output when empty
  • Collapsible accordion UI pattern
Phase 4

Admin Setup

Metafield Definitions
Admin metafield definitions
Product Values
Admin product metafield values

Settings → Custom data → Products — merchant-friendly setup

Phase 5

App Data: Collection Badge

Product Card with App Badge
Collection badge
  • Simulates external app data via app_data.* namespace
  • Double guard: badge_enabled + badge_text
  • Defensive coding — zero errors if app removed
  • Positioned independently from Sale/Sold Out badges
Phase 5

App Data: PDP Certifications

JSON Metafield → Structured UI
PDP certifications
  • extra_info JSON: warranty, origin, certifications[]
  • Each key checked independently before render
  • Certifications as pill tags via for cert in
  • App-uninstall safe — graceful degradation
Phase 6

Custom VAT Pricing

Inc/Exc Tax Toggle on PDP
VAT pricing display
  • Per-product custom.show_tax boolean metafield
  • Price incl. VAT & excl. VAT display
  • Sale price support with compare_at_price
  • Consistent across PDP, Collection, Cart
Phase 6

Price Logic

{%- Unified price snippet — PDP, Collection, Cart -%}

{%- assign show_tax = product.metafields.custom.show_tax.value -%}
{%- assign tax_rate = settings.tax_rate | divided_by: 100.0 -%}

{%- if show_tax -%}
  {%- assign price_inc = price | times: 1 -%}
  {%- assign price_exc = price | divided_by: tax_factor -%}

  <span class="price--inc">{{ price_inc | money }} incl. VAT</span>
  <span class="price--exc">{{ price_exc | money }} excl. VAT</span>
{%- endif -%}

{%- compare_at_price support for sale badges -%}
{%- if compare_at_price > price -%}
  <s class="price--was">{{ compare_at_price | money }}</s>
{%- endif -%}
Phase 7

JavaScript Interactions

Web Component

Product Tabs

Custom <product-tabs> element with keyboard navigation, ARIA attributes, and section rendering API

Web Component

Variant Picker

Dynamic variant selection updating price, availability, and images without page reload

Web Component

Sticky ATC

Intersection Observer-based sticky Add to Cart bar — appears on scroll past main button

Zero jQuery · Custom Elements API · Event Delegation · data-* Attributes

Phase 7

Product Tabs

Product tabs component

Description, Specifications, Shipping — accessible tab navigation with ARIA roles

Phase 7

Variant Picker & Sticky ATC

Tabs + Variant Selection
Tabs with variant picker
Sticky Add to Cart
Sticky add to cart bar
Phase 7

Web Components Pattern

class ProductTabs extends HTMLElement {
  constructor() {
    super();
    this.buttons = this.querySelectorAll('[role="tab"]');
    this.panels = this.querySelectorAll('[role="tabpanel"]');
  }

  connectedCallback() {
    this.addEventListener('click', this.handleClick);
    this.addEventListener('keydown', this.handleKeydown);
  }

  switchTab(target) {
    this.buttons.forEach(btn => btn.setAttribute('aria-selected', 'false'));
    target.setAttribute('aria-selected', 'true');
    // ... panel visibility logic
  }
}
customElements.define('product-tabs', ProductTabs);
Phase 8

Performance Optimizations

CSS

Deferred Styles

Non-critical CSS loaded asynchronously via media="print" swap pattern, eliminating render-blocking

Layout

Content Visibility

content-visibility: auto on below-fold sections, reducing initial rendering work by ~40%

Images

LCP Optimization

Hero image preload with fetchpriority="high", responsive srcset, WebP via Shopify CDN

Lazy Load

Smart Loading

loading="lazy" below fold, eager for LCP — no lazy on hero images

CLS

Layout Stability

Explicit width/height on all images, aspect-ratio CSS, no above-fold shifts

DOM

Minimal Markup

Semantic HTML, reduced wrapper nesting, efficient Liquid loops

Phase 8

Render-Blocking Reduction

<!-- Defer non-critical CSS -->
<link rel="stylesheet" href="component-card.css"
      media="print" onload="this.media='all'">

<!-- LCP hero preload -->
<link rel="preload" as="image" fetchpriority="high"
      href="{{ hero_image | image_url: width: 1200 }}"
      imagesrcset="...">

<!-- Content visibility for below-fold -->
.section--below-fold {
  content-visibility: auto;
  contain-intrinsic-size: auto 500px;
}

Every optimization follows Shopify best practices — no external dependencies needed

Summary

Skills Demonstrated

1
Theme Architecture — sections, snippets, JSON templates
2
Design Implementation — Figma to Liquid, mobile-first
3
Shopify 2.0 — dynamic blocks, admin customization
4
Metafields — text, boolean, JSON, conditional rendering
5
App Integration — resilient app-data handling
6
Custom Pricing — VAT logic across all surfaces
7
Vanilla JS — Web Components, ARIA, event delegation
8
Performance — deferred CSS, LCP, content-visibility

Thank You

WinSport Portfolio Theme

Shopify 2.0 · Liquid · Vanilla JS · Mobile-First · Dawn v15.4.1

Press Space or click to navigate · Auto-advances every 6 seconds