Free Size Chart Popup Section for ShopifyNo app. Copy, paste, done.
- Online Store 2.0
- No app
- Theme Check: 0 errors
- MIT license
The Stackframes size chart popup is a free Shopify section that adds a "Size guide" button to your product page. The button opens an accessible popup with your measurements table and an optional how-to-measure image. You type the columns and rows straight into the theme editor. It uses the browser's native dialog, so it works with the keyboard, closes with Escape, and needs no app or monthly fee.
Live preview with sample content. Once installed, fonts follow your theme and colours are editable in the theme editor.
{%- assign columns = section.settings.columns | split: ',' -%}
{%- if section.blocks.size > 0 or request.design_mode -%}
<sf-size-chart
class="sf-size"
style="--sf-size-text: {{ section.settings.text_color }}; --sf-size-accent: {{ section.settings.accent_color }}; --sf-size-bg: {{ section.settings.background_color }}; --sf-size-justify: {{ section.settings.alignment }}; --sf-size-pt: {{ section.settings.padding_top }}px; --sf-size-pb: {{ section.settings.padding_bottom }}px;"
>
<div class="sf-size__row">
<button type="button" class="sf-size__trigger" aria-haspopup="dialog" aria-controls="SfSizeDialog-{{ section.id }}">
<svg class="sf-size__trigger-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" width="20" height="20"><path d="M3 9h18v6H3z" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linejoin="round"/><path d="M7 9v3M11 9v2M15 9v3M19 9v2" stroke="currentColor" stroke-width="1.75" stroke-linecap="round"/></svg>
<span>{{ section.settings.button_label | escape }}</span>
</button>
</div>
<dialog class="sf-size__dialog" id="SfSizeDialog-{{ section.id }}" aria-labelledby="SfSizeTitle-{{ section.id }}">
<div class="sf-size__panel">
<div class="sf-size__header">
<h2 class="sf-size__title" id="SfSizeTitle-{{ section.id }}">{{ section.settings.heading | escape }}</h2>
<button type="button" class="sf-size__close" aria-label="Close size guide">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24" width="20" height="20"><path d="M6 6l12 12M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
</div>
{%- if section.settings.intro != blank -%}
<div class="sf-size__intro">{{ section.settings.intro }}</div>
{%- endif -%}
{%- if section.blocks.size > 0 -%}
<div class="sf-size__scroll" role="region" aria-label="{{ section.settings.heading | escape }}" tabindex="0">
<table class="sf-size__table">
{%- if section.settings.unit_note != blank -%}
<caption class="sf-size__caption">{{ section.settings.unit_note | escape }}</caption>
{%- endif -%}
<thead>
<tr>
{%- for column in columns -%}
<th scope="col">{{ column | strip | escape }}</th>
{%- endfor -%}
</tr>
</thead>
<tbody>
{%- for block in section.blocks -%}
{%- assign cells = block.settings.cells | split: ',' -%}
<tr {{ block.shopify_attributes }}>
{%- for cell in cells -%}
{%- if forloop.first -%}
<th scope="row">{{ cell | strip | escape }}</th>
{%- else -%}
<td>{{ cell | strip | escape }}</td>
{%- endif -%}
{%- endfor -%}
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
{%- else -%}
<p class="sf-size__empty">Add size rows to build your chart.</p>
{%- endif -%}
{%- if section.settings.guide_image != blank -%}
<figure class="sf-size__figure">
{{ section.settings.guide_image | image_url: width: 1200 | image_tag: widths: '400, 800, 1200', sizes: '(min-width: 760px) 680px, 90vw', loading: 'lazy', class: 'sf-size__image' }}
{%- if section.settings.guide_caption != blank -%}
<figcaption class="sf-size__figcaption">{{ section.settings.guide_caption | escape }}</figcaption>
{%- endif -%}
</figure>
{%- endif -%}
</div>
</dialog>
</sf-size-chart>
{%- endif -%}
{% stylesheet %}
.sf-size { display: block; color: var(--sf-size-text); padding: var(--sf-size-pt) 20px var(--sf-size-pb); }
.sf-size__row { display: flex; justify-content: var(--sf-size-justify); max-width: 1200px; margin: 0 auto; }
.sf-size__trigger { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 4px; border: 0; background: transparent; color: inherit; font: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 4px; cursor: pointer; }
.sf-size__trigger:focus-visible { outline: 2px solid var(--sf-size-accent); outline-offset: 2px; border-radius: 4px; }
.sf-size__dialog { width: min(720px, calc(100vw - 32px)); max-height: calc(100vh - 32px); padding: 0; border: 0; border-radius: 12px; background: var(--sf-size-bg); color: var(--sf-size-text); box-shadow: 0 24px 64px rgba(0, 0, 0, 0.25); }
.sf-size__dialog::backdrop { background: rgba(17, 24, 39, 0.55); }
.sf-size__panel { padding: 24px; }
.sf-size__header { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 12px; }
.sf-size__title { margin: 0; font-size: 1.375em; line-height: 1.2; }
.sf-size__close { display: grid; place-items: center; flex: none; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 999px; background: transparent; color: inherit; cursor: pointer; }
.sf-size__close:hover { background: color-mix(in srgb, currentColor 8%, transparent); }
.sf-size__close:focus-visible { outline: 2px solid var(--sf-size-accent); outline-offset: 2px; }
.sf-size__intro { margin-bottom: 16px; opacity: 0.8; }
.sf-size__intro > :first-child { margin-top: 0; }
.sf-size__intro > :last-child { margin-bottom: 0; }
.sf-size__scroll { overflow-x: auto; }
.sf-size__scroll:focus-visible { outline: 2px solid var(--sf-size-accent); outline-offset: 2px; }
.sf-size__table { width: 100%; min-width: 420px; border-collapse: collapse; font-size: 0.9375em; }
.sf-size__caption { padding-bottom: 8px; text-align: left; font-size: 0.875em; opacity: 0.75; }
.sf-size__table th, .sf-size__table td { padding: 10px 12px; border-bottom: 1px solid color-mix(in srgb, currentColor 14%, transparent); text-align: left; }
.sf-size__table thead th { font-weight: 700; background: color-mix(in srgb, currentColor 5%, transparent); }
.sf-size__table tbody th { font-weight: 600; }
.sf-size__figure { margin: 20px 0 0; }
.sf-size__image { display: block; width: 100%; height: auto; border-radius: 8px; }
.sf-size__figcaption { margin-top: 8px; font-size: 0.875em; opacity: 0.75; }
.sf-size__empty { margin: 0; padding: 20px; border: 1px dashed currentColor; border-radius: 8px; text-align: center; opacity: 0.7; }
{% endstylesheet %}
{% javascript %}
if (!customElements.get('sf-size-chart')) {
class SfSizeChart extends HTMLElement {
connectedCallback() {
this.onClick = (event) => {
const dialog = this.querySelector('dialog');
if (event.target.closest('.sf-size__trigger')) this.open();
else if (event.target.closest('.sf-size__close') || event.target === dialog) this.close();
};
this.onSelect = (event) => {
if (this.contains(event.target)) this.open();
};
this.onDeselect = (event) => {
if (this.contains(event.target)) this.close();
};
this.addEventListener('click', this.onClick);
document.addEventListener('shopify:block:select', this.onSelect);
document.addEventListener('shopify:block:deselect', this.onDeselect);
}
disconnectedCallback() {
this.removeEventListener('click', this.onClick);
document.removeEventListener('shopify:block:select', this.onSelect);
document.removeEventListener('shopify:block:deselect', this.onDeselect);
}
open() {
const dialog = this.querySelector('dialog');
if (!dialog || dialog.hasAttribute('open')) return;
if (typeof dialog.showModal === 'function') dialog.showModal();
else dialog.setAttribute('open', '');
}
close() {
const dialog = this.querySelector('dialog');
if (!dialog || !dialog.hasAttribute('open')) return;
if (typeof dialog.close === 'function') dialog.close();
else dialog.removeAttribute('open');
}
}
customElements.define('sf-size-chart', SfSizeChart);
}
{% endjavascript %}
{% schema %}
{
"name": "SF size chart",
"tag": "section",
"class": "sf-size-section",
"disabled_on": { "groups": ["header", "footer"] },
"max_blocks": 30,
"settings": [
{ "type": "text", "id": "button_label", "label": "Button label", "default": "Size guide" },
{
"type": "select",
"id": "alignment",
"label": "Button alignment",
"options": [
{ "value": "flex-start", "label": "Left" },
{ "value": "center", "label": "Center" },
{ "value": "flex-end", "label": "Right" }
],
"default": "flex-start"
},
{ "type": "text", "id": "heading", "label": "Popup heading", "default": "Size guide" },
{ "type": "richtext", "id": "intro", "label": "Intro text", "default": "<p>Measure over light clothing. If you are between sizes, size up for a relaxed fit.</p>" },
{ "type": "text", "id": "columns", "label": "Column headings", "info": "Separate with commas.", "default": "Size, Chest (cm), Waist (cm), Hips (cm)" },
{ "type": "text", "id": "unit_note", "label": "Table note", "default": "All measurements are body measurements in centimetres." },
{ "type": "image_picker", "id": "guide_image", "label": "How-to-measure image" },
{ "type": "text", "id": "guide_caption", "label": "Image caption" },
{ "type": "header", "content": "Colors" },
{ "type": "color", "id": "text_color", "label": "Text", "default": "#121212" },
{ "type": "color", "id": "accent_color", "label": "Accent", "default": "#121212" },
{ "type": "color", "id": "background_color", "label": "Popup background", "default": "#ffffff" },
{ "type": "header", "content": "Spacing" },
{ "type": "range", "id": "padding_top", "label": "Top padding", "min": 0, "max": 60, "step": 4, "unit": "px", "default": 8 },
{ "type": "range", "id": "padding_bottom", "label": "Bottom padding", "min": 0, "max": 60, "step": 4, "unit": "px", "default": 8 }
],
"blocks": [
{
"type": "size",
"name": "Size row",
"settings": [
{ "type": "text", "id": "cells", "label": "Row values", "info": "Separate with commas, matching the column headings. The first value is the size name.", "default": "M, 96–101, 81–86, 101–106" }
]
}
],
"presets": [
{
"name": "SF size chart",
"blocks": [
{ "type": "size", "settings": { "cells": "XS, 81–86, 66–71, 86–91" } },
{ "type": "size", "settings": { "cells": "S, 86–91, 71–76, 91–96" } },
{ "type": "size", "settings": { "cells": "M, 96–101, 81–86, 101–106" } },
{ "type": "size", "settings": { "cells": "L, 106–111, 91–96, 111–116" } },
{ "type": "size", "settings": { "cells": "XL, 116–121, 101–106, 121–126" } }
]
}
]
}
{% endschema %}
- Native dialog: keyboard, Escape and focus handled by the browser
- Columns and rows typed straight into the theme editor
- Optional how-to-measure image with caption
- Scrollable table on phones
- Opens automatically while you edit rows in the theme editor
Add the Size Chart Popup to your theme
About two minutes. No app, no monthly fee.
Prefer a walkthrough? See the full installation guide.
- STEP 01
Duplicate your theme
In Shopify admin go to Online Store → Themes. Next to your current theme click ⋯ → Duplicate. Make every change on the copy.
- STEP 02
Create the section file
On the copy, click ⋯ → Edit code. In the sections folder click “Add a new section”, choose Liquid, name it sf-size-chart-popup and create it. Delete the starter code, paste ours, then click Save.
- STEP 03
Add it to a page
Click Customize, open the template you want, click “Add section” and choose “SF size chart”. Edit the text, blocks and colours in the sidebar, then Save.
- STEP 04
Check it, then publish
Preview on mobile and desktop. When you are happy, publish the duplicate theme.
What you can change in the theme editor
| Setting | Type | Default |
|---|---|---|
| Button label | Text | Size guide |
| Button alignment | Dropdown | Left |
| Popup heading | Text | Size guide |
| Intro text | Rich text | Measure over light clothing. If you are between sizes, size up for a relaxed … |
| Column headingsSeparate with commas. | Text | Size, Chest (cm), Waist (cm), Hips (cm) |
| Table note | Text | All measurements are body measurements in centimetres. |
| How-to-measure image | Image | — |
| Image caption | Text | — |
| Text | Colour | #121212 |
| Accent | Colour | #121212 |
| Popup background | Colour | #ffffff |
| Top padding | Slider | 8px |
| Bottom padding | Slider | 8px |
| Setting | Type | Default |
|---|---|---|
| Row valuesSeparate with commas, matching the column headings. The first value is the size name. | Text | M, 96–101, 81–86, 101–106 |
This section is one piece of a custom theme.
We design and build complete Shopify themes around your brand.
Common questions
How do I show a different size chart per product?
Create an alternate product template for each chart type (for example tops and shoes), add this section to each, and assign products to the right template.
How do I enter the measurements?
Type the column headings separated by commas, then add a row block per size with its values separated by commas in the same order.
Can shoppers switch between centimetres and inches?
This version shows one unit system. Add a second row set in the other unit, or ask us to build a unit toggle into it.
More free sections
FAQ Accordion
Copy-paste FAQ accordion section for Shopify. Keyboard accessible, adds FAQPage structured data, works on Online Store 2.0 themes. No app needed.
Comparison Table
Free "us vs them" comparison table section for Shopify with check marks, text values and a highlighted column. Accessible HTML table, no app.
Before/After Slider
Free before and after image slider for Shopify. Drag the handle or use the keyboard to compare two photos. Accessible, lightweight Liquid, no app.
All free Shopify sections
Get a Shopify theme built around your brand
Custom sections, a full theme build, or changes to the theme you already have. Tell us what your store needs and we'll scope it with you.
Not affiliated with or endorsed by Shopify Inc. Shopify is a trademark of Shopify Inc.