@colabcommerce/elements
v0.11.2
Published
This library provides a set of foundational elements for customer facing Colab Commerce integrations. It supplies hooks and prebuilt elements.
Readme
Colab Commerce Elements
This library provides a set of foundational elements for customer facing Colab Commerce integrations. It supplies hooks and prebuilt elements.
React Version Support
This package supports both React 18 and React 19.
- react: >=18.0.0 <20.0.0
- react-dom: >=18.0.0 <20.0.0
Optional React Compiler
Builds do not enable the React Compiler by default to keep cross-version compatibility.
To enable it explicitly during build:
REACT_COMPILER=true npm run build
Installation
npm
npm install @colabcommerce/elements
yarn
yarn add @colabcommerce/elements
Documentation
https://www.colabcommerce.com/developers
Style Isolation
To protect against host-page CSS leaking into our components, both distributions render inside a Shadow DOM boundary.
IIFE widgets (CDN bundle)
window.ColabElements.mount(name, el, props) and the auto-scan of
[data-cc-widget] anchors both attach an open shadow root to the host
element, adopt the bundled stylesheet via adoptedStyleSheets (or an inline
<style> fallback on older engines), and render the component inside a
<div class="cc"> container inside the shadow root.
A :host { all: initial; display: block; … } reset wall blocks host-page
inherited properties (font-family, color, line-height, etc.) from cascading
into the shadow tree. Re-theming via CSS custom properties (--primary,
--background, …) continues to work because CSS variables defined on the
light-DOM host element are inherited across the shadow boundary.
To opt a single mount out of Shadow DOM (e.g. for debugging or legacy DOM
introspection), set the data-cc-no-shadow attribute on the anchor:
<div data-cc-widget="StoreLocator" data-cc-no-shadow data-config='…'></div>A regression page lives at playground/hostile.html
that mounts a widget alongside intentionally hostile global CSS for manual
visual verification.
React/npm consumers
The per-component entry points (@colabcommerce/elements/Button, etc.) are
unchanged and render in light DOM, since most React consumers control their
own page CSS.
When you need the same isolation as the IIFE bundle inside a React app, wrap
the subtree in the optional CCRoot wrapper. It attaches a shadow root, adopts
the same bundled stylesheet, and portals its children inside.
import CCRoot from '@colabcommerce/elements/CCRoot'
import StoreLocator from '@colabcommerce/elements/StoreLocator'
export default function Page() {
return (
<CCRoot>
<StoreLocator organizationId="…" />
</CCRoot>
)
}Theming and Style Overrides
There are three supported ways for an integrator to restyle the elements, listed in order of preference. All three work in both the IIFE/Shadow-DOM and light-DOM (npm React) mount paths.
1. CSS custom properties (recommended)
The components read every color, radius, and shadow value from CSS variables
defined on the .cc container (and mirrored on :host for the RPNI vars).
Custom properties inherit across the shadow boundary, so setting them on
the light-DOM host element (or on :root) re-themes everything inside,
including the shadow-mounted widgets.
/* on the integrator's page */
:root {
--primary: #ff5a1f;
--primary-foreground: #ffffff;
--radius: 0.5rem;
}
/* or scoped to a single mount */
#my-quote-widget {
--primary: #0f766e;
}Available variables
Color tokens (defined on .cc, dark variants on .cc.dark):
| Variable | Light default | Notes |
| --- | --- | --- |
| --background | #fdfdfd | Page/widget background |
| --foreground | #000000 | Default text |
| --card / --card-foreground | #fdfdfd / #000000 | Card surfaces |
| --popover / --popover-foreground | #fcfcfc / #000000 | Popover/dialog surfaces |
| --primary / --primary-foreground | #7033ff / #ffffff | Primary buttons, accents |
| --secondary / --secondary-foreground | #edf0f4 / #080808 | Secondary buttons |
| --muted / --muted-foreground | #f5f5f5 / #525252 | Muted surfaces and text |
| --accent / --accent-foreground | #e2ebff / #1e69dc | Hover/accent surfaces |
| --destructive / --destructive-foreground | #e54b4f / #ffffff | Errors, destructive actions |
| --border | #e7e7ee | Default border color |
| --input | #ebebeb | Input background/border |
| --ring | #000000 | Focus ring color |
| --chart-1 … --chart-5 | | Chart palette |
| --color-black / --color-white | | Literal black/white |
| --color-green / --color-orange / --color-red / --color-blue | | Brand status colors |
Sidebar tokens: --sidebar, --sidebar-foreground, --sidebar-primary,
--sidebar-primary-foreground, --sidebar-accent, --sidebar-accent-foreground,
--sidebar-border, --sidebar-ring.
Radius: --radius (default 1.4rem). Tailwind exposes
--radius-sm/md/lg/xl derived from this.
Shadow: --shadow-x, --shadow-y, --shadow-blur, --shadow-spread,
--shadow-opacity, --shadow-color. Tailwind exposes
--shadow-2xs/xs/sm/md/lg/xl/2xl derived from these.
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. Semantic cc-* hook classes (light-DOM consumers)
Each component's root and primary children carry stable cc-<component>
and cc-<component>__<part> classes alongside the Tailwind utilities.
These are only useful in the light-DOM path (data-cc-no-shadow or the
plain npm/React mount without <CCRoot>), because page CSS cannot reach
inside a shadow root.
.cc-quote-form-button__trigger {
background-color: #0f766e;
border-radius: 999px;
}
.cc-lead-form__submit {
text-transform: uppercase;
letter-spacing: 0.05em;
}Hooks shipped today:
| Component | Class | Part |
| --- | --- | --- |
| StoreLocator | .cc-store-locator | store-locator |
| | .cc-store-locator__layout | store-locator-layout |
| | .cc-store-locator__sidebar | store-locator-sidebar |
| | .cc-store-locator__search | store-locator-search |
| Store | .cc-store | store |
| | .cc-store__main | store-main |
| | .cc-store__details | store-details |
| | .cc-store__products-section | store-products-section |
| QuoteForm | .cc-quote-form | quote-form |
| QuoteFormButton | .cc-quote-form-button | quote-form-button |
| | .cc-quote-form-button__trigger | quote-form-button-trigger |
| | .cc-quote-form-button__overlay | quote-form-button-overlay |
| | .cc-quote-form-button__dialog | quote-form-button-dialog |
| LeadForm | .cc-lead-form | lead-form |
| | .cc-lead-form__actions | lead-form-actions |
| | .cc-lead-form__submit | lead-form-submit |
| | .cc-lead-form__cancel | lead-form-cancel |
3. ::part() selectors (Shadow-DOM consumers)
The same elements also carry a part="..." attribute. When mounted inside
Shadow DOM (IIFE auto-scan / mount() / <CCRoot>), integrators can style
those parts from the outer page using the standard ::part() selector:
my-quote-mount::part(quote-form-button-trigger) {
background: #ff5a1f;
border-radius: 999px;
}
my-quote-mount::part(lead-form-submit) {
text-transform: uppercase;
}<div id="my-quote-mount" data-cc-widget="QuoteFormButton" data-config='…'></div>::part() is the W3C-blessed way to expose styleable surfaces across the
shadow boundary, and it requires no opt-out of isolation.
CI Policy
The repository uses an incremental CI policy with deterministic required checks and separate optional smoke paths.
Required Checks
- Build and test matrix in
.github/workflows/ci.yml: Node 20/22 x React 18/19. - Required test command is coverage-enabled:
npm run test:ci. - PR-only blocking lint gate for changed JS/JSX files in
.github/workflows/ci.yml.
Optional Checks
- Full-repo lint remains advisory in
.github/workflows/ci.ymlwhile historical backlog is reduced. - Live API smoke workflow in
.github/workflows/live-api-smoke.ymlruns only on manual trigger and nightly schedule, and requires GitHub secrets. - Cypress component smoke workflow in
.github/workflows/cypress-smoke.ymlruns on manual trigger.
Deterministic vs Live Test Paths
- Deterministic required path: no secrets, mocked API tests in Vitest.
- Live optional path: secret-backed smoke checks for production-like endpoints.
Lint Rollout Stages
- Current stage: changed-files lint is blocking on PRs.
- Current stage: full-repo lint is advisory.
- Next stage target: promote full-repo lint to blocking after backlog burn-down criteria are met.
