@storesynk/elements
v0.1.0-beta.13
Published
Universal Storesynk web components — drop-in Shopify storefront UI for any site.
Maintainers
Readme
@storesynk/elements
Drop-in Shopify storefront web components for any site — product pages, collections,
search, and a cart — built on @storesynk/core.
One self-contained script, no build step, works anywhere HTML does (plain HTML or any
framework).
🧪 Early development — APIs may change. Full docs: docs.storesynk.com
Install
npm install @storesynk/elementsPre-1.0 prereleases (
0.1.0-beta.N) are published to npm'slatesttag, so a plain install gets the current release. Do not install@beta: that dist-tag is frozen at an old build.
Import it once anywhere in your bundle and every tag registers itself:
import '@storesynk/elements';Self-hosting instead of bundling? Copy the entire dist/ folder — storesynk.js is the
entry and lazy-loads sibling chunks (collection.js, pixels.js, …) relative to its own URL.
Use via a script tag
<script type="module" src="https://cdn.storesynk.io/elements/0.1/storesynk.js"></script>
<storesynk-store token="YOUR_PUBLIC_TOKEN" domain="your-store.myshopify.com">
<storesynk-product handle="my-product" class="product">
<h1 class="product__title"><show-title></show-title></h1>
<p class="product__price"><show-price class="price"></show-price></p>
<change-option group="1" class="options">
<value-option class="options__value"><show-label></show-label></value-option>
</change-option>
<change-quantity min="1" class="quantity">
<decrease-quantity class="quantity__btn">−</decrease-quantity>
<input-quantity class="quantity__field"></input-quantity>
<increase-quantity class="quantity__btn">+</increase-quantity>
</change-quantity>
<add-to-cart class="button button--primary">Add to cart</add-to-cart>
</storesynk-product>
</storesynk-store>Wrap the components in your own semantic HTML and classes — they only set the content,
you own the structure and styling. Every functional piece is its own tag; attributes only
ever carry context. (In HTML, custom elements need closing tags — <show-title></show-title>,
not <show-title/>.)
Variant URLs (sync-url)
Add sync-url to a page's main <storesynk-product> to mirror the variant selection in the
URL: the initial selection is read from the URL, option clicks replaceState it, and
back/forward re-derives it. Two link styles are read either way, matching Liquid storefronts and
Hydrogen: ?variant=<numeric id> (the reserved variant param, never an option name; it wins
when both are present) and one param per option (?color=red, matched case-insensitively).
The attribute value picks what gets written:
<storesynk-product handle="my-product" sync-url> <!-- writes ?color=red&size=m -->
<storesynk-product handle="my-product" sync-url="variant"> <!-- writes ?variant=41820371452004 -->sync-url="variant" writes the shareable Liquid-style link (falling back to option params
while the selection does not resolve to a variant). Stale option params and the variant param
are scrubbed before each write, other params (?ref=campaign) survive. Never put sync-url on
list or search card templates: they would all fight over one URL.
Components (selection)
- Context:
storesynk-store,storesynk-product - Displayers:
show-title,show-price,show-compare-price,show-image,show-media,show-sku,show-stock, … (hide themselves when empty) - Variant options:
change-option,value-option,show-label,show-swatch - Quantity:
change-quantity,increase-quantity,decrease-quantity,input-quantity,show-quantity - Actions:
add-to-cart,buy-now,product-link - Lists:
storesynk-list(simple collection),search-result-list+search-input,predictive-search - Collections (filterable grid, see below):
storesynk-collection,product-list,filter-list,change-filter,change-price,change-sort,load-more,clear-filters,active-filter-list,show-result-count - Cart:
storesynk-cart,cart-line-list,cart-line,show-line-*,increase-line-quantity,decrease-line-quantity,remove-cart-line,open-cart,close-cart,show-cart-count,show-cart-total,checkout-link - Pixels (analytics, optional): enable with
<storesynk-store track-events>— forwards commerce events to Meta, GA4, TikTok, Pinterest, Reddit, Klaviyo + Shopify native. When on, it loads Shopify's Customer Privacy API and storefront analytics scripts from cdn.shopify.com; consent is always enforced (the oldrequire-consentis accepted but no longer needed). Shopify's standard-actions CDN script is never loaded: Storesynk is that runtime. See PIXELS.md (shipped with the package).
Collections (product listing)
<storesynk-collection> renders a filterable, sortable, paginated product grid driven
entirely by the Shopify Storefront API — filtering, sorting and cursor pagination happen
server-side, so it stays fast on any catalog size. It loads on demand as a separate
collection.js chunk the first time a <storesynk-collection> appears on a page, so pages
that don't list products never download it.
<storesynk-collection handle="shoes" page-size="24">
<change-sort>
<select>
<option value="">Featured</option>
<option value="PRICE">Price, low to high</option>
<option value="PRICE:reverse">Price, high to low</option>
<option value="TITLE">Alphabetical</option>
<option value="CREATED:reverse">Newest</option>
</select>
</change-sort>
<!-- Applied-filter chips (first child is the chip template) -->
<active-filter-list>
<active-filter-item><show-filter-title></show-filter-title><button remove>×</button></active-filter-item>
</active-filter-list>
<clear-filters>Clear all</clear-filters>
<!-- Price range -->
<change-price>
<input min-input placeholder="Min" /> <input max-input placeholder="Max" />
<button apply>Go</button>
</change-price>
<!-- Zero-config checkbox facets for everything Search & Discovery exposes -->
<filter-list>
<filter-group>
<h4><show-filter-label></show-filter-label></h4>
<filter-value>
<label><input type="checkbox" /> <show-filter-title></show-filter-title> (<show-filter-count></show-filter-count>)</label>
</filter-value>
</filter-group>
</filter-list>
<!-- The grid: the first child is the card template, cloned per product -->
<product-list>
<storesynk-product class="card">
<product-link><a><show-title></show-title> <show-price></show-price></a></product-link>
</storesynk-product>
</product-list>
<p>Showing <show-result-count></show-result-count></p>
<load-more>Load more</load-more>
</storesynk-collection>Leave handle off to render the whole store — no collection needs to exist for this; the
engine lists the full catalog via a wildcard search (note: search only sorts by
RELEVANCE/PRICE, so other change-sort keys fall back to the default order there). If you
have a curated all-products collection, point all-handle at it to use that instead — real
collections support the full sort-key set and the merchant's merchandising.
Which filters appear, and how AND/OR works
The available filters — availability, price, product options, vendor, type, tag, metafields —
are whatever the merchant enables in Shopify's Search & Discovery app, not something the
component decides. Enable one there and it shows up automatically with live result counts. Within
a single filter, values combine with OR by default; product tags and list.* metafields can
be switched to AND in Search & Discovery. The component only sends the selected values, so the
AND/OR behavior always follows the store's configuration.
Custom filter UX (swatches, single/multi-select)
<filter-list> renders every filter uniformly as checkboxes. To style one filter yourself,
render it with <change-filter for="…"> and drop it from the auto list with
<filter-list except="color">. It clones your <filter-value> template per value — use any
markup you like (swatches, pills, image tiles) — and paints <show-filter-swatch> from the
value's swatch color/image when the merchant sets that filter to a swatch (or image) presentation.
<filter-list except="color"><!-- other filters render here --></filter-list>
<change-filter for="color" mode="multi">
<h4><show-filter-label></show-filter-label></h4>
<filter-value class="swatch">
<show-filter-swatch class="swatch__dot"></show-filter-swatch>
<show-filter-title class="swatch__name"></show-filter-title>
</filter-value>
</change-filter>for targets a filter by option name, label or id. mode="multi" (default) toggles values;
mode="single" keeps one selected at a time within the group.
Shareable URLs
Filters, sort and pagination are mirrored to the URL as readable params
(?color=Blue&price=10-50&sort=PRICE&page=2) so views are shareable, bookmarkable, SEO-friendly
and back/forward-restorable. With more than one collection on a page, give each a unique url-key
so their params don't collide (url-key="a" → ?a.color=Blue). Add no-url-sync to opt out.
License
MIT
