Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Shopify/horizon/llms.txt

Use this file to discover all available pages before exploring further.

Core Principles

Horizon is built on four foundational principles that should guide all development work:

Web-Native Development

Leverage modern web standards while maintaining backwards compatibility Horizon runs on the evergreen web, utilizing the latest browser features while supporting older browsers through progressive enhancement.
<!-- Base functionality works everywhere -->
<details class="accordion">
  <summary>Click to expand</summary>
  <div class="content">
    This works in all browsers without JavaScript
  </div>
</details>

<!-- Enhanced with JavaScript for better UX -->
<script>
  // Add smooth animations for modern browsers
  if ('animate' in Element.prototype) {
    // Progressive enhancement code
  }
</script>
Do not use polyfills. Use progressive enhancement and feature detection instead.

Lean and Fast

Functionality defaults to “no” until it meets performance requirements
  • Ship code based on quality, not quantity
  • Build with purpose - don’t support every feature
  • Optimize for Core Web Vitals (LCP, FID, CLS)
  • Keep JavaScript bundles minimal

Server-Rendered

HTML must be rendered by Shopify servers using Liquid Business logic and platform primitives belong on the server:
{%- assign sale_price = product.price | money -%}
{%- assign compare_price = product.compare_at_price | money -%}

<span class="price">{{ sale_price }}</span>
{%- if compare_price -%}
  <span class="price--compare">{{ compare_price }}</span>
{%- endif -%}

Functional Design

Functional across browsers, not pixel-perfect
  • Use semantic markup
  • Embrace progressive enhancement
  • Design for flexibility, not rigid pixel perfection
  • Test across multiple browsers and devices

Development Practices

File Organization

Store reusable, configurable content blocks in /sections/:
  • Use schema to define customization options
  • Keep sections focused on a single purpose
  • Use theme blocks for modular content
  • Follow naming convention: main-*.liquid for template sections
Store reusable Liquid code in /snippets/:
  • Keep snippets small and focused
  • Use descriptive names that indicate purpose
  • Document required parameters in comments
  • Prefix utility snippets with util-
{%- comment -%}
  Renders a product price
  
  Parameters:
  - product: Product object
  - show_compare: Boolean (optional)
{%- endcomment -%}
Organize assets by type:
  • *.css - Stylesheets (prefer modern CSS over preprocessors)
  • *.js - JavaScript modules
  • Images - Optimized and properly sized
  • Fonts - Use Shopify’s font library when possible
/config/ contains:
  • settings_schema.json - Theme settings definition
  • settings_data.json - Theme settings values (don’t commit in Git)

Liquid Best Practices

{%- liquid
  # Cleaner, more readable Liquid
  assign product_available = true
  if product.available == false
    assign product_available = false
  endif
-%}

JavaScript Best Practices

// Use modules
export class ProductForm {
  constructor(element) {
    this.element = element;
    this.form = element.querySelector('form');
    this.init();
  }
  
  init() {
    this.form?.addEventListener('submit', this.handleSubmit.bind(this));
  }
  
  handleSubmit(event) {
    event.preventDefault();
    // Handle form submission
  }
}

// Use optional chaining and nullish coalescing
const productTitle = product?.title ?? 'Untitled Product';

CSS Best Practices

:root {
  --color-primary: #000F9F;
  --color-text: #000000;
  --spacing-unit: 1rem;
  --font-body: system-ui, sans-serif;
}

.button {
  background-color: var(--color-primary);
  padding: calc(var(--spacing-unit) * 0.75) var(--spacing-unit);
  font-family: var(--font-body);
}

Performance Optimization

Image Optimization

{%- liquid
  assign sizes = 'sizes="(min-width: 990px) 50vw, 100vw"'
  assign widths = '375, 550, 750, 1100, 1500, 1780, 2000, 3000'
-%}

<img
  srcset="{{ product.featured_image | image_url: width: 375 }} 375w,
          {{ product.featured_image | image_url: width: 750 }} 750w,
          {{ product.featured_image | image_url: width: 1100 }} 1100w"
  {{ sizes }}
  src="{{ product.featured_image | image_url: width: 750 }}"
  alt="{{ product.featured_image.alt | escape }}"
  loading="lazy"
  width="{{ product.featured_image.width }}"
  height="{{ product.featured_image.height }}"
>

JavaScript Performance

  • Defer non-critical JavaScript: Use defer attribute on script tags
  • Code splitting: Load features only when needed
  • Minimize DOM manipulation: Batch updates and use DocumentFragment
  • Debounce expensive operations: Use debounce for scroll/resize handlers

CSS Performance

  • Critical CSS inline: Inline above-the-fold CSS
  • Avoid @import: Use link tags or bundle CSS
  • Minimize specificity: Keep selectors simple
  • Use CSS containment: Apply contain property where appropriate

Accessibility

Use proper HTML elements:
<!-- Good -->
<header>...</header>
<nav>...</nav>
<main>...</main>
<footer>...</footer>

<!-- Bad -->
<div class="header">...</div>
<div class="nav">...</div>
Enhance accessibility with ARIA:
<button
  aria-expanded="false"
  aria-controls="menu-drawer"
  aria-label="Open menu"
>
  Menu
</button>

<div
  id="menu-drawer"
  aria-hidden="true"
  role="dialog"
>
  <!-- Drawer content -->
</div>
Ensure all interactive elements are keyboard accessible:
  • Use native buttons and links when possible
  • Implement proper focus management
  • Provide visible focus indicators
  • Support keyboard shortcuts (Escape to close modals)
Maintain WCAG AA compliance:
  • Text: minimum 4.5:1 contrast ratio
  • Large text: minimum 3:1 contrast ratio
  • Interactive elements: 3:1 contrast ratio
  • Use tools to verify contrast ratios

Testing

Theme Check

Run Theme Check before committing changes:
shopify theme check
Horizon includes Theme Check in the VS Code extensions. Install it for real-time linting.

Browser Testing

Test across multiple browsers:
  • Chrome/Edge (Chromium)
  • Firefox
  • Safari (macOS and iOS)
  • Mobile browsers

Accessibility Testing

  • Keyboard navigation: Tab through the entire page
  • Screen readers: Test with VoiceOver (macOS) or NVDA (Windows)
  • Automated tools: Use Lighthouse, axe DevTools
  • Color contrast: Use browser DevTools or online checkers

Performance Testing

  • Lighthouse: Run audits in Chrome DevTools
  • WebPageTest: Test from different locations and connections
  • Core Web Vitals: Monitor LCP, FID, CLS

Version Control

Git Workflow

# Create feature branch
git checkout -b feature/product-card-enhancement

# Make changes and commit
git add .
git commit -m "Add hover effect to product cards"

# Push to remote
git push origin feature/product-card-enhancement

# Create pull request for review

What to Commit

Do commit:
  • Theme files (sections, snippets, templates, layouts)
  • Assets (CSS, JS, images)
  • Configuration schema (settings_schema.json)
  • Documentation
Don’t commit:
  • settings_data.json (contains store-specific data)
  • .DS_Store or OS-specific files
  • Node modules or dependencies
  • Generated files

Security

Never expose sensitive data in theme code. Use Shopify’s secure APIs for handling customer data.

Input Sanitization

{%- comment -%} Always escape user input {%- endcomment -%}
<p>{{ customer.name | escape }}</p>

{%- comment -%} Use appropriate filters {%- endcomment -%}
<a href="{{ product.url | url_escape }}">{{ product.title | escape }}</a>

Content Security

  • Use {{ content_for_header }} for required Shopify scripts
  • Avoid inline JavaScript when possible
  • Validate and sanitize all form inputs
  • Use HTTPS for all external resources

Documentation

Code Comments

{%- comment -%}
  Renders a product card
  
  Usage:
    {% render 'product-card', product: product, show_vendor: true %}
  
  Parameters:
  - product: Product object (required)
  - show_vendor: Boolean - Display vendor name (optional, default: false)
  - image_ratio: String - 'square' or 'portrait' (optional, default: 'square')
{%- endcomment -%}

Schema Documentation

{
  "type": "range",
  "id": "products_per_row",
  "label": "Products per row (desktop)",
  "info": "Adjust the number of products displayed in each row on desktop screens",
  "min": 2,
  "max": 5,
  "step": 1,
  "default": 4
}

Resources

Build docs developers (and LLMs) love