Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
benjaminsehl avatar

Liquid Theme Standards

  • 2.3k installs
  • 115 repo stars
  • Updated July 16, 2026
  • benjaminsehl/liquid-skills

liquid-theme-standards is an agent skill that CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet tags, design t.

About

CSS JS HTML Standards for Shopify Liquid Themes 1 Progressive enhancement semantic HTML first CSS second JS third 2 No external dependencies native browser APIs only for JavaScript 3 Design tokens never hardcode colors spacing or fonts 4 BEM naming consistent class naming throughout 5 Defensive CSS handle edge cases gracefully Location Liquid Use For stylesheet No Component scoped styles one per file style Yes Dynamic values needing Liquid e g color settings assets css No Shared global styles Critical stylesheet does NOT process Liquid Use inline style attributes for dynamic values liquid comment Do inline variables endcomment div class hero style bg color section settings bg_color padding section settings padding px The liquid theme standards agent skill provides documented workflows prerequisites triggers and safety guidance from its SKILL md source Agents load it when user requests match the description and follow step by step instructions without inventing capabilities It integrates with standard agent tooling for the tasks inputs outputs and failure modes described in the repository documentation

  • description: "CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet
  • 1. **Progressive enhancement** — semantic HTML first, CSS second, JS third
  • 2. **No external dependencies** — native browser APIs only for JavaScript
  • Follow liquid-theme-standards SKILL.md steps and documented constraints.
  • Follow liquid-theme-standards SKILL.md steps and documented constraints.

Liquid Theme Standards by the numbers

  • 2,279 all-time installs (skills.sh)
  • +64 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #475 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

liquid-theme-standards capabilities & compatibility

Capabilities
description: "css, javascript, and html coding s · 1. **progressive enhancement** — semantic html f · 2. **no external dependencies** — native browser · follow liquid theme standards skill.md steps and
Use cases
orchestration
From the docs

What liquid-theme-standards says it does

description: "CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet tags, design tokens, CSS custom properties, Web Components for themes, defensive
SKILL.md
1. **Progressive enhancement** — semantic HTML first, CSS second, JS third
SKILL.md
2. **No external dependencies** — native browser APIs only for JavaScript
SKILL.md
npx skills add https://github.com/benjaminsehl/liquid-skills --skill liquid-theme-standards

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs2.3k
repo stars115
Security audit3 / 3 scanners passed
Last updatedJuly 16, 2026
Repositorybenjaminsehl/liquid-skills

When should an agent use liquid-theme-standards and what problem does it solve?

CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet tags, design tokens, CSS custom properties, Web Components for themes, defensive CSS, and prog

Who is it for?

Developers invoking liquid-theme-standards as documented in the skill source.

Skip if: Skip when requirements fall outside liquid-theme-standards documented scope.

When should I use this skill?

CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet tags, design tokens, CSS custom properties, Web Components for themes, defensive CSS, and prog

What you get

Outputs aligned with the liquid-theme-standards SKILL.md workflow and stated deliverables.

  • section Liquid templates
  • scoped CSS stylesheets
  • settings-driven design tokens

Files

SKILL.mdMarkdownGitHub ↗

CSS, JS & HTML Standards for Shopify Liquid Themes

Core Principles

1. Progressive enhancement — semantic HTML first, CSS second, JS third 2. No external dependencies — native browser APIs only for JavaScript 3. Design tokens — never hardcode colors, spacing, or fonts 4. BEM naming — consistent class naming throughout 5. Defensive CSS — handle edge cases gracefully

CSS in Liquid Themes

Where CSS Lives

LocationLiquid?Use For
{% stylesheet %}NoComponent-scoped styles (one per file)
{% style %}YesDynamic values needing Liquid (e.g., color settings)
assets/*.cssNoShared/global styles

Critical: {% stylesheet %} does NOT process Liquid. Use inline style attributes for dynamic values:

{%- comment -%} Do: inline variables {%- endcomment -%}
<div
  class="hero"
  style="--bg-color: {{ section.settings.bg_color }}; --padding: {{ section.settings.padding }}px;"
>

{%- comment -%} Don't: Liquid inside stylesheet {%- endcomment -%}
{% stylesheet %}
  .hero { background: {{ section.settings.bg_color }}; } /* Won't work */
{% endstylesheet %}

BEM Naming Convention

.block                      → Component root: .product-card
.block__element             → Child: .product-card__title
.block--modifier            → Variant: .product-card--featured
.block__element--modifier   → Element variant: .product-card__title--large

Rules:

  • Hyphens separate words: .product-card, not .productCard
  • Single element level only: .block__element, never .block__el1__el2
  • Modifier always paired with base class: class="btn btn--primary", never class="btn--primary" alone
  • Start new BEM scope when a child could be standalone
<!-- Good: single element level -->
<div class="product-card">
  <h3 class="product-card__title">{{ product.title }}</h3>
  <span class="product-card__button-label">{{ 'add_to_cart' | t }}</span>
</div>

<!-- Good: new BEM scope for standalone component -->
<div class="product-card">
  <button class="button button--primary">
    <span class="button__label">{{ 'add_to_cart' | t }}</span>
  </button>
</div>

Specificity

  • Target 0 1 0 (single class) wherever possible
  • Maximum 0 4 0 for complex parent-child cases
  • Never use IDs as selectors
  • Never use !important (comment why if absolutely forced to)
  • Avoid element selectors — use classes

CSS Nesting

/* Do: media queries inside selectors */
.header {
  width: 100%;

  @media screen and (min-width: 750px) {
    width: auto;
  }
}

/* Do: state modifiers with & */
.button {
  background: var(--color-primary);

  &:hover { background: var(--color-primary-hover); }
  &:focus-visible { outline: 2px solid var(--color-focus); }
  &[disabled] { opacity: 0.5; }
}

/* Do: parent modifier affecting children (single level) */
.card--featured {
  .card__title { font-size: var(--font-size-xl); }
}

/* Don't: nested beyond first level */
.parent {
  .child {
    .grandchild { } /* Too deep */
  }
}

Design Tokens

Use CSS custom properties for all values — never hardcode colors, spacing, or fonts. Define a consistent scale and reference it everywhere.

Example scale (adapt to your theme's needs):

:root {
  /* Spacing — use a consistent scale */
  --space-2xs: 0.5rem;    --space-xs: 0.75rem;   --space-sm: 1rem;
  --space-md: 1.5rem;     --space-lg: 2rem;       --space-xl: 3rem;

  /* Typography — relative units */
  --font-size-sm: 0.875rem;  --font-size-base: 1rem;
  --font-size-lg: 1.125rem;  --font-size-xl: 1.25rem;  --font-size-2xl: 1.5rem;
}

Key principles:

  • Use rem for spacing and typography (respects user font size preferences)
  • Name tokens semantically: --space-sm not --space-16
  • Define in :root for global tokens, on component root for scoped tokens

CSS Variable Scoping

Global — in :root for theme-wide values Component-scoped — on component root, namespaced:

/* Do: namespaced */
.facets {
  --facets-padding: var(--space-md);
  --facets-z-index: 3;
}

/* Don't: generic names that collide */
.facets {
  --padding: var(--space-md);
  --z-index: 3;
}

Override via inline style for section/block settings:

<section
  class="hero"
  style="
    --hero-bg: {{ section.settings.bg_color }};
    --hero-padding: {{ section.settings.padding }}px;
  "
>

CSS Property Order

1. Layoutposition, display, flex-direction, grid-template-columns 2. Box modelwidth, margin, padding, border 3. Typographyfont-family, font-size, line-height, color 4. Visualbackground, opacity, border-radius 5. Animationtransition, animation

Logical Properties (RTL Support)

/* Do: logical properties */
padding-inline: 2rem;
padding-block: 1rem;
margin-inline: auto;
border-inline-end: 1px solid var(--color-border);
text-align: start;
inset: 0;

/* Don't: physical properties */
padding-left: 2rem;
text-align: left;
top: 0; right: 0; bottom: 0; left: 0;

Defensive CSS

.component {
  overflow-wrap: break-word;        /* Prevent text overflow */
  min-width: 0;                     /* Allow flex items to shrink */
  max-width: 100%;                  /* Constrain images/media */
  isolation: isolate;               /* Create stacking context */
}

.image-container {
  aspect-ratio: 4 / 3;             /* Prevent layout shift */
  background: var(--color-surface); /* Fallback for missing images */
}

Modern CSS Features

/* Container queries for responsive components */
.product-grid { container-type: inline-size; }
@container (min-width: 400px) {
  .product-card { grid-template-columns: 1fr 1fr; }
}

/* Fluid spacing */
.section { padding: clamp(1rem, 4vw, 3rem); }

/* Intrinsic sizing */
.content { width: min(100%, 800px); }

Performance

  • Animate only transform and opacity (never layout properties)
  • Use will-change sparingly — remove after animation
  • Use contain: content for isolated rendering
  • Use dvh instead of vh on mobile

Reduced Motion

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

JavaScript in Liquid Themes

Where JS Lives

LocationLiquid?Use For
{% javascript %}NoComponent-specific scripts (one per file)
assets/*.jsNoShared utilities, Web Components

Web Component Pattern

class ProductCard extends HTMLElement {
  connectedCallback() {
    this.button = this.querySelector('[data-add-to-cart]');
    this.button?.addEventListener('click', this.#handleClick.bind(this));
  }

  disconnectedCallback() {
    // Clean up event listeners, abort controllers
  }

  async #handleClick(event) {
    event.preventDefault();
    this.button.disabled = true;

    try {
      const formData = new FormData();
      formData.append('id', this.dataset.variantId);
      formData.append('quantity', '1');

      const response = await fetch('/cart/add.js', {
        method: 'POST',
        body: formData
      });

      if (!response.ok) throw new Error('Failed');

      this.dispatchEvent(new CustomEvent('cart:item-added', {
        detail: await response.json(),
        bubbles: true
      }));
    } catch (error) {
      console.error('Add to cart error:', error);
    } finally {
      this.button.disabled = false;
    }
  }
}

customElements.define('product-card', ProductCard);
<product-card data-variant-id="{{ product.selected_or_first_available_variant.id }}">
  <button data-add-to-cart>{{ 'products.add_to_cart' | t }}</button>
</product-card>

JavaScript Rules

RuleDoDon't
Loopsfor (const item of items)items.forEach()
Asyncasync/await.then() chains
Variablesconst by defaultlet unless reassigning
ConditionalsEarly returnsNested if/else
URLsnew URL() + URLSearchParamsString concatenation
DependenciesNative browser APIsExternal libraries
Private methods#methodName()_methodName()
TypesJSDoc @typedef, @param, @returnsUntyped

AbortController for Fetch

class DataLoader extends HTMLElement {
  #controller = null;

  async load(url) {
    this.#controller?.abort();
    this.#controller = new AbortController();

    try {
      const response = await fetch(url, { signal: this.#controller.signal });
      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      return await response.json();
    } catch (error) {
      if (error.name !== 'AbortError') throw error;
      return null;
    }
  }

  disconnectedCallback() {
    this.#controller?.abort();
  }
}

Component Communication

Parent → Child: Call public methods

this.querySelector('child-component')?.publicMethod(data);

Child → Parent: Dispatch custom events

this.dispatchEvent(new CustomEvent('child:action', {
  detail: { value },
  bubbles: true
}));

HTML Standards

Native Elements First

NeedUseNot
Expandable<details>/<summary>Custom accordion with JS
Dialog/modal<dialog>Custom overlay div
Tooltip/popuppopover attributeCustom positioned div
Search form<search><div class="search">
Form results<output><span class="result">

Progressive Enhancement

{%- comment -%} Works without JS {%- endcomment -%}
<details class="accordion">
  <summary>{{ block.settings.heading }}</summary>
  <div class="accordion__content">
    {{ block.settings.content }}
  </div>
</details>

{%- comment -%} Enhanced with JS {%- endcomment -%}
{% javascript %}
  // Optional: smooth animation, analytics tracking
{% endjavascript %}

Images

{{ image | image_url: width: 800 | image_tag:
  loading: 'lazy',
  alt: image.alt | escape,
  width: image.width,
  height: image.height
}}
  • loading="lazy" on all below-fold images
  • Always set width and height to prevent layout shift
  • Descriptive alt text; empty alt="" for decorative images

JSON Template & Config Files

Theme templates (templates/*.json), section groups (sections/*.json), and config files (config/settings_data.json) are all JSON. Use jq via the bash tool to make surgical edits — it's safer and more reliable than string-based find-and-replace for structured data.

Common patterns

# Add a section to a template
jq '.sections.new_section = {"type": "hero", "settings": {"heading": "Welcome"}}' templates/index.json > /tmp/out && mv /tmp/out templates/index.json

# Update a setting value
jq '.current.sections.header.settings.logo_width = 200' config/settings_data.json > /tmp/out && mv /tmp/out config/settings_data.json

# Reorder sections
jq '.order += ["new_section"]' templates/index.json > /tmp/out && mv /tmp/out templates/index.json

# Remove a section
jq 'del(.sections.old_banner) | .order -= ["old_banner"]' templates/index.json > /tmp/out && mv /tmp/out templates/index.json

# Read a nested value
jq '.sections.header.settings' templates/index.json

Prefer `jq` over `edit` for any .json file modification — it validates structure, handles escaping, and avoids whitespace/formatting issues.

References

  • CSS patterns and examples
  • JavaScript patterns and examples

Related skills

Forks & variants (1)

Liquid Theme Standards has 1 known copy in the catalog totaling 119 installs. They canonicalize to this original listing.

How it compares

Pick liquid-theme-standards over generic CSS skills when authoring Shopify Liquid section files that need settings-driven tokens and {% stylesheet %} co-location.

FAQ

What is liquid-theme-standards?

CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet tags, design tokens, CSS custom properties, Web Components for themes, def

When should I use liquid-theme-standards?

CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet tags, design tokens, CSS custom properties, Web Components for themes, def

Is liquid-theme-standards safe to install?

Review the Security Audits panel on this page before production use.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.