Widgets — JavaScript SDK
The same store locator, quote form, and store detail experiences from @colabcommerce/elements — built into a browser-ready bundle for non-React pages. Drop in a CSS file, a script tag, and a data-cc-widget element to mount.
On this page
Introduction
The Widgets SDK is a precompiled browser bundle that exposes three mountable widgets on the same global used by the WordPress integration — window.ColabCommerce. Internally it renders the same React components as @colabcommerce/elements, so behavior, props, and providers match. You do not need React, a bundler, or any context wiring on the host page.
Three widgets are exposed: StoreLocator, QuoteForm, and Store.
Assets
The SDK is served from the Colab Commerce CDN:
- Stylesheet —
https://cdn.colabcommerce.com/elements.1.2.0.css - Script —
https://cdn.colabcommerce.com/elements.v1.2.0.js
Reference both the JS and CSS files in your page. Pin both URLs to a specific version — window.ColabCommerce.version reports the running version at runtime.
Quick start
Two ways to mount: declarative (auto-scan on load) or programmatic (when you need callbacks or dynamic props).
<link rel="stylesheet" href="https://cdn.colabcommerce.com/elements.1.2.0.css" />
<div
data-cc-widget="StoreLocator"
data-config='{"organizationId":"4f155976-8631-445a-b1b7-c8ccac28cca1","locale":"en"}'
></div>
<script src="https://cdn.colabcommerce.com/elements.v1.2.0.js"></script><link rel="stylesheet" href="https://cdn.colabcommerce.com/elements.1.2.0.css" />
<div id="locator"></div>
<script src="https://cdn.colabcommerce.com/elements.v1.2.0.js"></script>
<script>
const el = document.getElementById('locator')
window.ColabCommerce.mount('StoreLocator', el, {
organizationId: '4f155976-8631-445a-b1b7-c8ccac28cca1',
locale: 'en',
showProducts: true,
productLimit: 12,
baseUrl: '/retailers',
})
</script>When the script loads, the SDK scans the document for any[data-cc-widget] elements and mounts each one using the JSON in its data-config attribute. Callbacks cannot be expressed in JSON — use a programmatic mount when you need onClose, onSuccess, or other functions.
SDK surface
The SDK exposes a single global runtime object, window.ColabCommerce. In addition to the widget mount helpers, it exposes a quote registry for quote-form widgets and the instance-level methods used to mutate the current products and open/close quote flows.
interface ColabCommerce {
mount(name: 'StoreLocator' | 'Store' | 'QuoteForm' | 'QuoteFormButton', element: Element, props: Record<string, any>): void
unmount(element: Element): void
scan(root?: Element | Document): void
version: string
quote: {
all(): QuoteInstance[]
get(target?: Element | string): QuoteInstance | undefined
setProducts(products: Product[]): void
ready(callback: (api: QuoteInstance) => void): void
register(api: QuoteInstance): void
unregister(api: QuoteInstance): void
}
}mount
MethodMount a widget instance into a DOM element with the given props. This is the primary programmatic entry point when you want callbacks or dynamic values.
window.ColabCommerce.mount('QuoteFormButton', document.getElementById('quote'), {
organizationId: 'org_123',
products: [{ sku: 'ABC-1', name: 'Aluminum Chaise' }],
onSuccess: ({ lead }) => console.log('lead created', lead),
})unmount
MethodDestroy the widget mounted on an element and remove its React root. Use this during route changes or when removing the widget from the DOM.
const el = document.getElementById('quote')
window.ColabCommerce.unmount(el)scan
MethodScan a document or root node for [data-cc-widget] anchors and mount any unmounted widgets automatically.
window.ColabCommerce.scan(document)
// or: window.ColabCommerce.scan(document.querySelector('#widget-root'))quote.all
MethodReturn every mounted quote instance so you can iterate or drive multiple quote widgets on one page.
const instances = window.ColabCommerce.quote.all()
instances.forEach((quote) => {
quote.setProducts([{ sku: 'ABC-1' }])
})quote.get
MethodResolve a single quote instance by element or CSS selector.
const quote = window.ColabCommerce.quote.get('#quote')
quote?.setProducts([{ sku: 'ABC-2' }])quote.setProducts
MethodSet the product list on every mounted quote instance in a single call. This is useful when your cart changes globally.
window.ColabCommerce.quote.setProducts([
{ sku: 'ABC-1', name: 'Aluminum Chaise' },
{ sku: 'ABC-2', name: 'Patio Side Table' },
])quote.ready
MethodRegister a callback that fires for all current quote instances and any quote instance that mounts later.
window.ColabCommerce.quote.ready((api) => {
api.setProducts([{ sku: 'ABC-1' }])
})getProducts
InstanceRead a copy of the current product list from a single quote instance.
const quote = window.ColabCommerce.quote.get('#quote')
const products = quote.getProducts()
console.log(products)setProducts
InstanceReplace the current quote products on a specific instance and re-render the widget with the new selection.
quote.setProducts([
{ sku: 'ABC-1', name: 'Aluminum Chaise' },
{ sku: 'ABC-2', name: 'Patio Side Table' },
])addProduct
InstanceAppend a single product to the instance without clearing the current selection.
quote.addProduct({ sku: 'ABC-3', name: 'Sunbrella Cushion' })removeProduct
InstanceRemove one or more products from the instance by exact value or by a predicate function.
quote.removeProduct((product) => product.sku === 'ABC-3')
// or: quote.removeProduct({ sku: 'ABC-2', name: 'Patio Side Table' })clearProducts
InstanceClear the current selection for a single instance.
quote.clearProducts()reset
InstanceRestore the instance to its default empty state.
quote.reset()open / close
InstanceOpen or close dialog-based quote widgets, such as off-canvas or modal quote flows.
quote.open()
// later...
quote.close()on / off
InstanceSubscribe and unsubscribe to instance events like quote-ready and product-change notifications.
quote.on('cce-quote:productschange', ({ detail }) => {
console.log('products changed', detail.products)
})
quote.off('cce-quote:productschange')Widget reference
Three widgets are mountable through the SDK registry. All config props are forwarded directly to the underlying React component, so their behavior mirrors the matching entry in Elements.
StoreLocator
Full store locator experience with search, map, list, and message dialog. Internally wraps its own TranslationsProvider, StoreLocatorProvider, and APIProvider — no external context required.
Props
organizationId— string — requiredlocale— stringshowProducts— boolean — default falseproductLimit— number — default 10baseUrl— string — default /retailers
{
"organizationId": "YOUR_ORG_ID",
"locale": "en",
"showProducts": true,
"productLimit": 12,
"baseUrl": "/retailers"
}QuoteForm
Multi-step quote request flow: search a store, submit the lead, render a success state. Wraps its own TranslationsProvider and QuoteFormProvider internally, and uses Google Maps where needed.
Props
organizationId— string — requiredproducts— arraylocale— stringonClose— functiononSuccess— function
{
"organizationId": "YOUR_ORG_ID",
"locale": "en",
"products": [
{ "sku": "SKU-1", "name": "Product 1" }
]
}Note: function props like onClose and onSuccess cannot be supplied via JSON. Use a programmatic mount whenever you need them.
Store
Store detail page widget — store info, contact, map, and products. Wraps its own TranslationsProvider and StoreProvider internally.
Props
storeId— string — requiredlocale— string — default "en"initialData— object
{
"storeId": "STORE_ID",
"locale": "en"
}Mounting patterns
Auto-scan
Add one or more elements with data-cc-widget and data-config, include the SDK script, and the SDK will scan and mount them automatically on DOMContentLoaded.
Manual scan
After dynamically injecting widget elements into the page, ask the SDK to scan for them using the same global surface:
window.ColabCommerce.scan(document)Unmount
When removing a widget — for example, during a SPA route change — unmount it first:
const el = document.getElementById('locator')
window.ColabCommerce.unmount(el)Styling
Every widget mounts inside an open Shadow DOM boundary so that host-page CSS cannot leak in and break the layout. The bundled stylesheet is adopted into each shadow root automatically (via adoptedStyleSheets, with an inline <style> fallback on older engines), and a :host { all: initial; display: block; … } reset wall blocks inherited typography and colors from the surrounding page.
Because the shadow boundary blocks normal selectors, styling the widgets from your page CSS uses one of three supported mechanisms — listed in order of preference:
- CSS custom properties set on the host element (or
:root) — inherit across the shadow boundary. ::part()selectors targeting exposed shadow parts from outside.- Opt out of Shadow DOM with
data-cc-no-shadowand target thecc-*hook classes directly.
1. CSS custom properties (recommended)
The widgets read every color, radius, and shadow value from CSS variables defined on the .cc container (and mirrored on :host for the phone-input variables). Custom properties inherit through the shadow boundary, so setting them on the light-DOM host element — or globally on :root — re-themes the widget without any other configuration.
/* Re-theme every Colab widget on the page */
:root {
--primary: #ff5a1f;
--primary-foreground: #ffffff;
--radius: 0.5rem;
}/* Scoped to a single anchor */
#my-quote-widget {
--primary: #0f766e;
--primary-foreground: #ffffff;
--radius: 999px;
}Available tokens
Colors (light defaults; dark variants are applied when .cc.dark is present):
- Surfaces —
--background,--foreground,--card/--card-foreground,--popover/--popover-foreground,--muted/--muted-foreground - Actions —
--primary/--primary-foreground,--secondary/--secondary-foreground,--accent/--accent-foreground,--destructive/--destructive-foreground - Chrome —
--border,--input,--ring - Charts & status —
--chart-1…--chart-5,--color-green,--color-orange,--color-red,--color-blue,--color-black,--color-white - Sidebar —
--sidebar,--sidebar-foreground,--sidebar-primary/--sidebar-primary-foreground,--sidebar-accent/--sidebar-accent-foreground,--sidebar-border,--sidebar-ring
Radius — --radius (default 1.4rem). Derived utility steps --radius-sm, --radius-md, --radius-lg, and --radius-xl are exposed automatically.
Shadow — --shadow-x, --shadow-y, --shadow-blur, --shadow-spread, --shadow-opacity, --shadow-color. Derived steps --shadow-2xs through --shadow-2xl are exposed automatically.
Phone input (react-phone-number-input, defined on :host, .cc) — --PhoneInput-color--focus, --PhoneInputCountryFlag-height, --PhoneInputCountryFlag-aspectRatio, --PhoneInputCountryFlag-borderColor, --PhoneInputCountryFlag-borderColor--focus, --PhoneInputCountryFlag-borderWidth, --PhoneInputCountryFlag-backgroundColor--loading, --PhoneInputCountrySelect-marginRight, --PhoneInputCountrySelectArrow-width, --PhoneInputCountrySelectArrow-marginLeft, --PhoneInputCountrySelectArrow-borderWidth, --PhoneInputCountrySelectArrow-opacity, --PhoneInputCountrySelectArrow-color, --PhoneInputCountrySelectArrow-color--focus, --PhoneInputCountrySelectArrow-transform, --PhoneInputInternationalIconPhone-opacity, --PhoneInputInternationalIconGlobe-opacity.
2. ::part() selectors
For changes that go beyond what the design tokens expose — bespoke gradients, custom border treatments, typography overrides — every widget's key surfaces carry a part attribute. Standard W3C ::part() selectors style them from outside the shadow root, with no opt-out required.
<div
id="my-quote-mount"
data-cc-widget="QuoteForm"
data-config='{"organizationId":"YOUR_ORG_ID","locale":"en"}'
></div>Exposed parts
- StoreLocator —
store-locator,store-locator-layout,store-locator-sidebar,store-locator-search - Store —
store,store-main,store-details,store-products-section - QuoteForm —
quote-form,quote-form-button,quote-form-button-trigger,quote-form-button-overlay,quote-form-button-dialog,lead-form,lead-form-actions,lead-form-submit,lead-form-cancel
3. Light-DOM opt-out
For debugging, legacy DOM introspection, or when an existing design system needs to reach inside the widget with regular selectors, add the data-cc-no-shadow attribute to the mount anchor. The widget will render in the light DOM and your page CSS will apply normally — including against the stable cc-<component> and cc-<component>__<part> hook classes that mirror the shadow parts.
<div
data-cc-widget="StoreLocator"
data-cc-no-shadow
data-config='{"organizationId":"YOUR_ORG_ID","locale":"en"}'
></div>Opting out of Shadow DOM also removes the isolation wall — any global CSS on the host page (resets, utility frameworks, base typography) will cascade into the widget. Prefer CSS variables or ::part() selectors when possible and use data-cc-no-shadow only when you accept that trade-off.
Errors & debug behavior
- Invalid JSON in
data-configlogs a console warning and falls back to an empty config. - An unknown widget name logs a console warning and skips the mount.
- Calling
mount()without an element throws an error. - Repeated
mount()calls on the same element are ignored until the element isunmount()ed.
Limits
- Only
StoreLocator,QuoteForm, andStoreare mountable through the SDK registry. - Other entries published by @colabcommerce/elements are not exposed on
window.CCWidgetsunless added to the registry in a future SDK build. - The version in your script tag must match the built SDK filename — confirm via
window.CCWidgets.version.
Bundles are produced by yarn build:widgets (or yarn build:all) in the @colabcommerce/elements repo.
