storesynk-store
Section titled “storesynk-store”- Purpose: root provider. Boots
@storesynk/core(creates the Storefront client, installs thewindow.Shopify.actionsstandard-actions runtime + cart store, fetches the shop’smoneyFormat/currency), and providesstoreContextto the whole subtree. - Attributes:
token : string = ""- Storefront API public access token.domain : string = ""- store domain (e.g.your-store.myshopify.com).country : string = ""- optional ISO country for@inContextpricing. The initial market; a persisted buyer choice (seepersist-locale) wins over it at bootstrap, and the Markets pickers switch it at runtime.language : string = ""- optional language for@inContext. Same persisted-choice precedence ascountry.persist-locale : "cookie" | "localStorage" | "none" = "cookie"- (Markets) how the buyer’s country/language choice persists across visits.cookie(default) writesstoresynk_locale=<COUNTRY>/<LANGUAGE>- server-readable, so SSR routes can render the buyer’s market (the buyer-market SSR recipe depends on it);localStorageuses the key_storesynk-locale(client-only opt-out);nonedisables persistence. A persisted choice overrides thecountry/languageattributes at boot. (The default waslocalStoragebefore this version.)track-events- (optional pixels module) boolean; presence enables the analytics module (a separatepixels.jschunk, loaded on demand). Fires standard storefront events to any onsite pixels it detects (Meta, GA, TikTok, Pinterest, Reddit, Klaviyo).track-client : string- (pixels) comma-separated allow-list pinning which client pixels run (meta,ga,tiktok,pinterest,reddit,klaviyo), e.g.track-client="meta,ga". Absent = all auto-detected pixels run. Use it when you already fire events through some pixels yourself (e.g. via GTM) and want to avoid double-counting. (The oldtrack-excludedeny-list was removed - replace it with atrack-clientallow-list naming the providers you do want; without one, every detected provider runs.)require-consent- (pixels) boolean; gate tracking on the visitor’s consent.track-server : string- (pixels) opt into server-side forwarding to the Storesynk relay (the paid pipeline, which authors the real provider calls from the shop’s stored config). The value is a comma-separated provider list declaring which providers are handled server-side (track-server="meta,ga"); presence of the attribute (even bare) enables the relay beacon. Meta dedups client+server via the shared event id, so it may run both ways; GA cannot dedup, sogaintrack-serveralways drops its client pixel (server wins - GA never runs both ways). Requirestrack-events. NOT a URL - the endpoint override moved torelay-endpoint.relay-endpoint : string- (pixels) override the default relay endpoint with a self-hosted URL (e.g.relay-endpoint="https://…/collect"); only meaningful alongsidetrack-server.customer-client-id : string- (customer-accounts module) the Shopify Customer Account API OAuth client id (shp_…). Presence enables a separatecustomer.jschunk (loaded on demand): login, theshow-customer-*displayers, buyer-identified carts, and<storesynk-customer-pricing>. Absent = no customer module at all.customer-redirect-uri : string- (customer) the OAuth callback URL (must be allow-listed in the app’s Customer Account API config). Defaults to the current page’s origin + pathname.customer-account-pages : "shopify" | "custom" = "shopify"- (customer) where<account-link>sends the customer:shopify(default) = the hosted customer-account portal (derived from the shop’s OAuth discovery documents);custom= the site’s own pages atcustomer-account-url.customer-account-url : string- (customer) the account destination URL. Required forcustomer-account-pages="custom"; ignored inshopifymode.
- Required ancestor / context: none - the root. Provides
storeContext. One per page/tree; never nest (rule SSK-104). - Children: wrap your entire storefront markup inside it.
- Events: consumes (catches + stops)
sf:country-change/sf:language-changefrom the Markets pickers and owns the switch; emitssf:locale-change(bubbles, composed;detail = { country, language }) after a completed switch. With the customer module enabled, also emitssf:customer-change(bubbles, composed;detail = { customer },nullon logout) whenever the login state settles. - State it sets:
[ss-loading](+aria-busy="true") on itself during a locale switch;[ss-logged-in]while a customer session is logged in (the CSS hook for auth-gated UI - client and SSR); otherwise none. (domain/tokenmay be injected by a script before registration - see SSK-206.)
storesynk-product
Section titled “storesynk-product”- Purpose: product provider + state owner. Fetches a product by
handleorproduct-id, or is fed already-fetched data by a list/search container viaprovideProduct()(in which case it carries nohandle/product-id- correct). Owns runtime selection state (selectedVariant,selectedOptions,activeMediaIndex,quantity) and catches childsf:*events to update it. - Attributes:
handle : string = ""- product handle to fetch. Wins if both are set.product-id : string = ""- numeric id orgid://shopify/Product/…to fetch.revalidate- boolean; only meaningful after SSR payload adoption. After hydrating from an embedded payload, background-refetch the product and re-provide context only if it changed, preserving the user’s current selection. Keeps static builds fresh without a rebuild; a no-op on a normal client-fetched product. (See Server-side rendering & adoption.)sync-url- boolean; mirror the selected option(s) into the page URL. On everysf:option-changethe element writes the option name/value into URL query params viahistory.replaceState(no navigation, no history spam), and it adopts option state back from the URL on load and onpopstate(browser back/forward) - withsync-urlset, the URL wins over the default-variant selection. Off by default (nothing touches the URL). Use it so a chosen variant is shareable/bookmarkable and survives back/forward.
- Required ancestor / context:
storesynk-store(consumesstoreContext). ProvidesproductContext. Never nest inside anotherstoresynk-product(SSK-103). - Children: any product displayers/controls. As a list/search item template it must hold exactly one product subtree.
- Events: consumes (catches + stops)
sf:option-change,sf:media-select,sf:quantity-change; emitssf:variant-change(bubbles, composed) on selection change. - State it sets:
[ss-out-of-stock]/[ss-unavailable](mutually exclusive) on itself, tracking the selected variant’s availability - the passive sold-out hook for cards/grids with no buy button (storesynk-product[ss-out-of-stock] img { filter: grayscale(1) }). Set by the SSR transform too, so built HTML carries it pre-JS. Never add a hiddenadd-to-cartto a card just to read its state - this hook replaces that.
storesynk-cart
Section titled “storesynk-cart”- Purpose: cart drawer shell. Registers the
openCartstandard-action override so the global open action opens this drawer. Owns open/close and reflects cart emptiness. While open it is a modal dialog (dialog archetype): the engine setsrole="dialog"+aria-modal+ a fallbackaria-label(“Shopping cart” - author your own to override), moves focus in, traps Tab inside, closes on Escape, and returns focus to the opener on close. All of that applies only between open and close - the same tag used as an always-visible cart page (never opened as a drawer) keeps plain semantics. Don’t hand-roll Escape/focus handling. Closed-state CSS must includevisibility: hiddenif it only transforms the drawer off-screen (off-screen buttons are still tabbable). - Attributes:
open-on-add : boolean- opens the drawer after a successful add-to-cart (listens for the post-successsf:add-to-cartevent; a failed add never pops it). This is the DEFAULT behavior - a bare<storesynk-cart>already opens on add, so you rarely need the attribute. The site-wide opt-out is{"cart":{"openOnAdd":false}}in thedata-storesynk-configblock;open-on-addon the tag only exists to force the drawer back on over that opt-out. Omit both on a<storesynk-cart>used as an always-visible cart page only if a config opt-out is in play - otherwise it opens on add regardless.close-on-outside : boolean- a pointerdown outside the open drawer closes it (style your own scrim; clicks on it count as outside, no handler needed). - Required ancestor / context:
storesynk-store(consumesstoreContext). - Children: your drawer markup; typically a
cart-line-list, totals, andcheckout-link. - Events: none (open/close via the global action /
close-cart/ Escape). - State it sets:
[ss-open]and[ss-empty](no lines, or no cart created yet) on itself -[ss-empty]is the styling hook for a “your cart is empty” message (storesynk-cart[ss-empty] .empty-message { display:block }); never use an action tag as that message container.
cart-line-list
Section titled “cart-line-list”- Purpose: renders the cart’s lines. Captures its first
cart-linechild as a template, removes it, then clones it per line (driven by core’srichCartobservable) and feeds each clone viaprovideLine(). - Attributes: none.
- Required ancestor / context:
storesynk-store(consumesstoreContext); typically placed insidestoresynk-cart. - Children / template rule: TEMPLATE-CLONE - the first
cart-linechild is the template; missing → renders nothing (SSK-107). - Events: none.
- State it sets: none.
cart-line
Section titled “cart-line”- Purpose: one cart line; provides
cartLineContextto theshow-line-*displayers and exposes a.lineproperty the line controls read. - Attributes: none.
- Required ancestor / context:
cart-line-list(SSK-106). ProvidescartLineContext. - Children:
show-line-*displayers andincrease-line-quantity/decrease-line-quantity/remove-cart-linecontrols. - Events: none.
- State it sets: none.
Imported from the Storesynk skill v0.1.0 (references/component-reference.md). To change this page, change it there.