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 a single global — window.CCWidgets. 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.0.9.7.css - Script —
https://cdn.colabcommerce.com/elements.v0.9.7.js
Reference both the JS and CSS files in your page. Pin both URLs to a specific version — window.CCWidgets.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.0.9.7.css" />
<div
data-cc-widget="StoreLocator"
data-config='{"organizationId":"4f155976-8631-445a-b1b7-c8ccac28cca1","locale":"en"}'
></div>
<script src="https://cdn.colabcommerce.com/elements.v0.9.7.js"></script><link rel="stylesheet" href="https://cdn.colabcommerce.com/elements.0.9.7.css" />
<div id="locator"></div>
<script src="https://cdn.colabcommerce.com/elements.v0.9.7.js"></script>
<script>
const el = document.getElementById('locator')
window.CCWidgets.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.CCWidgets:
interface CCWidgets {
/** Mount a widget by name onto an element with the given props. */
mount(name: 'StoreLocator' | 'QuoteForm' | 'Store', element: Element, props: object): void
/** Unmount whatever widget is currently mounted on the element. */
unmount(element: Element): void
/** Scan a root (or document) for [data-cc-widget] elements and mount them. */
scan(root?: Element | Document): void
/** Bundle version string, matches the SDK filename. */
version: string
}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:
window.CCWidgets.scan(document)Unmount
When removing a widget — for example, during a SPA route change — unmount it first:
const el = document.getElementById('locator')
window.CCWidgets.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.
