Cart Feedback (Toasts & Button Loading)
When a shopper adds, updates, or removes a cart item on your theme, the FairShare SDK can surface the result for you — a toast confirms success or reports a failure, and add-to-cart buttons show a spinner while the request is in flight. Both are opt-in (off by default).
This page is for theme authors: how to enable, style, and localize them from your theme.
This is the theme-facing guide. For the full event payloads and JavaScript API, see the SDK reference: Cart Operation Events.
The mental model
- Your theme's buttons drive cart mutations — usually via
data-fluid-add-to-cart(see Product Bundles and the cart docs). - Once enabled, the SDK renders the toast and manages button spinners for you when a mutation settles — no per-element wiring.
- You enable and configure it from your theme's own JavaScript with
FairShareSDK.configureCartFeedback(...), and style it with your theme CSS.
Because the toast renders in the light DOM, your theme's CSS applies to it directly — no Shadow DOM to pierce.
Turning it on
The features can be toggled with data-fluid-toast="true" / data-fluid-button-loading="true" attributes on the Fluid <script> tag — but that script is usually a global embed injected into the page, which a theme can't edit. So from a theme, enable and configure them at runtime instead:
<!-- Anywhere in your theme, e.g. layout/theme.liquid --> <script> window.addEventListener("DOMContentLoaded", () => { window.FairShareSDK?.configureCartFeedback({ toast: true, buttonLoading: true, position: "bottom-right", class: "theme-toast", }); }); </script>
Notes:
- Call it inside
DOMContentLoaded— the SDK embed loads asynchronously, so it may not be attached yet when your inline script first runs. The optional chaining (?.) makes it a safe no-op if so. - Pass only the fields you want. The config is read lazily (at toast-show / button-click time) and merges over any
data-fluid-*script-tag attributes — precedence isconfigureCartFeedback()> attributes > defaults. So if you do control the embed, the attributes still work as a baseline. - The
CART_OPERATION_SUCCESS/CART_OPERATION_ERRORevents fire regardless — to render your own UI instead, just don't settoast: trueand listen to those.
All config keys
| Key | Type | Description |
|---|---|---|
toast | boolean | Enable the built-in toast |
buttonLoading | boolean | Enable the auto-spinner on declarative add-to-cart / enrollment buttons |
position | string | bottom-center (default), bottom-left, bottom-right, top-center, top-left, top-right |
class | string | Class added to the toast element (style variants in CSS via data-variant) |
duration | number | Auto-dismiss delay in ms (default 4000) |
icon | boolean | Show the variant icon (default true) |
successIcon / errorIcon / closeIcon | string | Custom icon — emoji, text, or SVG markup |
messages | object | { add, update, remove, error } message overrides |
Styling the toast
You don't need a class at all — the toast always has id="fluid-toast" and a data-variant attribute, so you can target it directly:
/* assets/custom.css */ #fluid-toast { border-radius: var(--border_radius, 8px); font-family: var(--font_family); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); } #fluid-toast[data-variant="success"] { background: var(--primary_color, #0f9d58); color: #fff; } #fluid-toast[data-variant="error"] { background: #d93025; color: #fff; }
Prefer your own class? Pass class to configureCartFeedback({ class: "theme-toast" }) and style .theme-toast[data-variant="error"] instead. Either way, style each variant off the data attributes the toast exposes:
| Data attribute on the toast | Values | Target it for |
|---|---|---|
data-variant | success / error | Success vs. error styling |
data-position | the configured position | Position-specific tweaks |
data-state | open / closed | Enter/exit styling |
Translating the copy
Pass messages to override the defaults per category. In a Liquid theme the inline script is rendered server-side, so you can pull the copy from your locale files and the toast follows the shopper's language.
Run each string through the json filter instead of wrapping it in quotes yourself. | json emits a fully escaped JavaScript string literal — its own quotes included — so a translation that contains an apostrophe, a quote, or a backslash can't break the script. Note there are no surrounding " in the snippet below; json supplies them:
<script> window.addEventListener("DOMContentLoaded", () => { window.FairShareSDK?.configureCartFeedback({ toast: true, messages: { add: {{ 'cart.added' | t | json }}, update: {{ 'cart.updated' | t | json }}, remove: {{ 'cart.removed' | t | json }}, error: {{ 'cart.error' | t | json }}, }, }); }); </script>
| tis the Liquid translation filter and| jsonescapes the result for the JavaScript string — swap| tfor your theme's localization helper if it differs. Thecart.*keys are an example, not built-ins: add them (and their translations) to your theme'slocales/*.jsonfiles first, and keep the namespace consistent between the snippet and the files. A key that isn't defined renders a visible "translation missing" string into the toast rather than falling back to the default.
| Message key | Default |
|---|---|
add | Added to cart |
update | Cart updated |
remove | Removed from cart |
error | Something went wrong. Please try again. |
Loading buttons
With buttonLoading: true, buttons wired with data-fluid-add-to-cart or data-fluid-add-enrollment-pack show a spinner automatically while their request runs — no per-button theme code. Add data-fluid-loading-text to swap the label while loading:
<button data-fluid-add-to-cart="{{ product.variant_id }}" data-fluid-loading-text="Adding…"> {{ 'product.add_to_cart' | t }} </button>
The spinner inherits the button's text color, so it matches your theme without extra CSS.
If your theme runs a cart mutation from its own JavaScript (custom payloads, dynamic bundles), wrap the call so the spinner is handled for you — this works even without buttonLoading enabled:
button.addEventListener("click", (e) => { window.FairShareSDK.withButtonLoading(e.currentTarget, () => window.FairShareSDK.addCartItems(variantId, { quantity: 1 }), ); });
See Cart Operation Events → Button Loading Indicator for setButtonLoading and the full API.
Putting it together
A theme that enables, styles, localizes, and gets loading add-to-cart buttons:
<!-- layout/theme.liquid --> <button data-fluid-add-to-cart="{{ product.variant_id }}" data-fluid-loading-text="{{ 'product.adding' | t }}"> {{ 'product.add_to_cart' | t }} </button> <script> window.addEventListener("DOMContentLoaded", () => { window.FairShareSDK?.configureCartFeedback({ toast: true, buttonLoading: true, position: "bottom-right", class: "theme-toast", messages: { add: {{ 'cart.added' | t | json }}, error: {{ 'cart.error' | t | json }}, }, }); }); </script>
/* assets/custom.css */ .theme-toast { border-radius: var(--border_radius, 8px); } .theme-toast[data-variant="success"] { background: var(--primary_color); color: #fff; } .theme-toast[data-variant="error"] { background: #d93025; color: #fff; }
Related
- Cart Operation Events — event payloads and JavaScript API
- Product Bundles — bundle add-to-cart buttons
- Developer Guide — building and customizing themes
- Affiliate Hydration — other light-DOM SDK behaviors in themes