NEW Browse AI tools across categories — updated daily. See what's new →

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…

Authorshopify
Version1.0.0
LicenseMIT
Token count~3,202
UpdatedJun 5, 2026

Install

Quick install

via npx skills · works with 57+ agents
npx skills add https://github.com/shopify/liquid-skills/tree/HEAD/plugins/liquid-skills/skills/liquid-theme-standards
Or pick agent:
npx skills add shopify/liquid-skills --skill liquid-theme-standards --agent claude-code
npx skills add shopify/liquid-skills --skill liquid-theme-standards --agent cursor
npx skills add shopify/liquid-skills --skill liquid-theme-standards --agent codex
npx skills add shopify/liquid-skills --skill liquid-theme-standards --agent opencode
npx skills add shopify/liquid-skills --skill liquid-theme-standards --agent github-copilot
npx skills add shopify/liquid-skills --skill liquid-theme-standards --agent windsurf
More install options

Shorthand — useful for multi-skill repos:

npx skills add shopify/liquid-skills --skill liquid-theme-standards

Manual — clone the repo and drop the folder into your agent's skills directory:

git clone https://github.com/shopify/liquid-skills.git
cp -r liquid-skills/plugins/liquid-skills/skills/liquid-theme-standards ~/.claude/skills/
How to use: Once installed, ask your agent to "use the liquid-theme-standards skill" or describe what you want (e.g. "CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM"). Requires Node.js 18+.

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…

liquid-theme-standardsby shopify

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

npx skills add https://github.com/shopify/liquid-skills --skill liquid-theme-standardsDownload ZIPGitHub

CSS, JS & HTML Standards for Shopify Liquid Themes

Core Principles

  • Progressive enhancement — semantic HTML first, CSS second, JS third
  • No external dependencies — native browser APIs only for JavaScript
  • Design tokens — never hardcode colors, spacing, or fonts
  • BEM naming — consistent class naming throughout
  • 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

  • Layout — position, display, flex-direction, grid-template-columns
  • Box model — width, margin, padding, border
  • Typography — font-family, font-size, line-height, color
  • Visual — background, opacity, border-radius
  • Animation — transition, 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'tLoopsfor (const item of items)items.forEach()Asyncasync/await.then() chainsVariablesconst by defaultlet unless reassigningConditionalsEarly returnsNested if/elseURLsnew URL() + URLSearchParamsString concatenationDependenciesNative browser APIsExternal librariesPrivate 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

NeedUseNotExpandable<details>/<summary>Custom accordion with JSDialog/modal<dialog>Custom overlay divTooltip/popuppopover attributeCustom positioned divSearch 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

More skills from shopify

agent-deviceby shopifyInteract with iOS simulator or Android emulator/device using snapshot-based coordinates. Uses accessibility tree snapshots for precise element targeting, with…analyze-feedbackby shopifyAnalyze agent feedback artifacts from GitHub Actions workflow runs, extract actionable learnings, and incorporate them into skill files and CLAUDE.md. Tracks…fix-github-issueby shopifyFull workflow for fixing a GitHub issue - understand the problem, reproduce, diagnose root cause, fix, test on iOS/Android simulators, review, and raise a PRraise-prby shopifyCreate a GitHub PR for FlashList. Ensures no AI/Claude attribution in commits or PR body, follows repo conventions for title, description, and test plan.review-and-testby shopifyReview a FlashList PR or branch, run unit tests, test on iOS simulator, and verify RTL/LTR behavior. Shared context with fix-github-issue skill.triage-issueby shopifyTriage a GitHub issue — classify priority (P0/P1/P2), search for duplicates, and apply labels.upgrade-react-nativeby shopifyUpgrade the React Native fixture app to a new version. Covers JS deps, Android (Gradle, Kotlin, SDK), iOS (Podfile, pbxproj), Metro config, and third-party…liquid-theme-a11yby shopifyImplement WCAG 2.2 accessibility patterns in Shopify Liquid themes. Covers e-commerce-specific components including product cards, carousels, cart drawers,…

---

Source: https://github.com/shopify/liquid-skills/tree/HEAD/plugins/liquid-skills/skills/liquid-theme-standards
Author: shopify
Discovered via: mcpservers.org

SKILL.md source

---
name: liquid-theme-standards
description: CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet tags, design tokens, CSS custom properties, Web…
---

# 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…

# liquid-theme-standardsby shopify
CSS, JavaScript, and HTML coding standards for Shopify Liquid themes. Covers BEM naming inside stylesheet tags, design tokens, CSS custom properties, Web…

`npx skills add https://github.com/shopify/liquid-skills --skill liquid-theme-standards`Download ZIPGitHub

## CSS, JS & HTML Standards for Shopify Liquid Themes

## Core Principles

* Progressive enhancement — semantic HTML first, CSS second, JS third

* No external dependencies — native browser APIs only for JavaScript

* Design tokens — never hardcode colors, spacing, or fonts

* BEM naming — consistent class naming throughout

* 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/*.css`NoShared/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

* Layout — `position`, `display`, `flex-direction`, `grid-template-columns`

* Box model — `width`, `margin`, `padding`, `border`

* Typography — `font-family`, `font-size`, `line-height`, `color`

* Visual — `background`, `opacity`, `border-radius`

* Animation — `transition`, `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/*.js`NoShared 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'tLoops`for (const item of items)``items.forEach()`Async`async`/`await``.then()` chainsVariables`const` by default`let` unless reassigningConditionalsEarly returnsNested `if/else`URLs`new URL()` + `URLSearchParams`String concatenationDependenciesNative browser APIsExternal librariesPrivate methods`#methodName()``_methodName()`TypesJSDoc `@typedef`, `@param`, `@returns`Untyped

### 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

NeedUseNotExpandable`<details>/<summary>`Custom accordion with JSDialog/modal`<dialog>`Custom overlay divTooltip/popup`popover` attributeCustom positioned divSearch 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

## More skills from shopify
agent-deviceby shopifyInteract with iOS simulator or Android emulator/device using snapshot-based coordinates. Uses accessibility tree snapshots for precise element targeting, with…analyze-feedbackby shopifyAnalyze agent feedback artifacts from GitHub Actions workflow runs, extract actionable learnings, and incorporate them into skill files and CLAUDE.md. Tracks…fix-github-issueby shopifyFull workflow for fixing a GitHub issue - understand the problem, reproduce, diagnose root cause, fix, test on iOS/Android simulators, review, and raise a PRraise-prby shopifyCreate a GitHub PR for FlashList. Ensures no AI/Claude attribution in commits or PR body, follows repo conventions for title, description, and test plan.review-and-testby shopifyReview a FlashList PR or branch, run unit tests, test on iOS simulator, and verify RTL/LTR behavior. Shared context with fix-github-issue skill.triage-issueby shopifyTriage a GitHub issue — classify priority (P0/P1/P2), search for duplicates, and apply labels.upgrade-react-nativeby shopifyUpgrade the React Native fixture app to a new version. Covers JS deps, Android (Gradle, Kotlin, SDK), iOS (Podfile, pbxproj), Metro config, and third-party…liquid-theme-a11yby shopifyImplement WCAG 2.2 accessibility patterns in Shopify Liquid themes. Covers e-commerce-specific components including product cards, carousels, cart drawers,…

---

**Source**: https://github.com/shopify/liquid-skills/tree/HEAD/plugins/liquid-skills/skills/liquid-theme-standards
**Author**: shopify
**Discovered via**: mcpservers.org