Skip to content

Integration caveats ​

Cross-widget integration caveats for every shipped GomaPulse widget: initialization, theming, sizing, SSR/webview constraints, and event correctness. Companion to cross-widget wiring and shared state. goma:* event naming and detail-shape parity across sibling widgets is tracked separately and not covered on this page.

Cross-cutting caveats ​

Importing a widget package outside a browser throws immediately ​

Every widget's element class is built on @gomagaming/core's createWidgetElement() factory (23 of 25 packages) or, for the two chat widgets, its own HTMLElement subclass declared directly (live-chat, messenger). In both cases the class that extends HTMLElement is defined at module top level: the moment the package is imported, not when the element is actually mounted. In a context with no HTMLElement global (a Next.js/Nuxt server render, or any Node import path without a DOM shim), importing any of the 26 widget packages throws a ReferenceError immediately, before any registration guard runs: the existing typeof customElements !== 'undefined' guards only wrap customElements.define(...), not the class-definition step that already ran during import.

If your host application does server-side rendering, dynamic-import every @gomagaming/* widget package behind a client-only boundary (Nuxt's <ClientOnly>, Next's dynamic(() => import(...), { ssr: false })). Importing at the top of a shared/universal module is not safe today.

Setting a property before the widget's definition has loaded ​

A custom element sits in the DOM as an ordinary unknown element until its class is registered. Anything you assign in that window (el.config = {…}) lands as a plain own property on the instance, and own properties shadow the accessors the element installs when it upgrades.

Widgets now rescue those assignments: on connect they remove the shadowing property and replay the value through the accessor, so a property set before the definition arrived still applies. It runs after the element's attributes are read, so an explicit property assignment still wins over the same key in markup, and before the first render, so a selection seeded this way stays silent exactly as one seeded from an attribute does. Properties the element has no setter for are left untouched.

On 0.34.0 and earlier the value was silently discarded. The widget mounted, emitted ready, and rendered nothing, with a clean console, which reads like a data or network problem rather than a configuration one.

Whether this can happen to you depends on how you load the widgets:

How you loadExposed?
Bundled, with a static import of the packageNo: the import is evaluated before your code runs
CDN loaderYes: the loader installs its import map synchronously but imports the widget modules asynchronously, so your module script routinely runs first
await import(...) before configuringNo
Attributes only (sport-id="8"), any loading methodNo: attributes survive upgrade untouched

The CDN row is the one that bites, because the documented integration (set .config on the element) is exactly the shape affected. On an older release set, await window.__gomaCdn.ready before assigning, or configure through attributes.

Locale is a shared singleton across every widget on the page ​

@gomagaming/core syncs a module-level i18n singleton to the current widget's locale on every mount and every locale change, so a handful of shared utility functions can read the active locale without being passed it explicitly. Because @gomagaming/core dedupes to one module instance across every @gomagaming/* widget on a page (the intended, documented dedup story, see installation), this singleton is genuinely shared, not scoped to instances of one widget type. Mounting two different widgets with two different locale values on one page means whichever mounted or changed locale most recently wins for any of those shared utilities.

If your integration needs multiple widgets on one page in different locales, be aware this is not currently isolated per widget instance: see Known issues being addressed separately.

Dates follow that locale, and English is rendered day-first: a widget configured with locale: 'en' writes a kick-off as 11 October, matching the compact 11/10 the event cards use and the day-first order every other shipped locale produces. A host that wants American ordering asks for it explicitly with locale: 'en-US'. This covers the dates these widgets render from a match's start time: event cards, the game-details header, the hero card, the banners, the search results, the My Bets legs and the live-chat bet modal. Dates that are not a match start time are a separate story: the missions surfaces still format challenge dates with the browser's locale rather than the widget's, and render the same instant as a fixed DD/MM/YY a few lines further down, so that view disagrees with itself whatever locale you set.

Theme-token registries commonly drift from what a widget actually paints ​

Most widget packages ship a src/themeTokens.js file that drives the playground's live theme editor. This registry can drift out of sync with the tokens a widget's CSS/components actually consume and with what its own docs page documents: a token missing from the registry means the playground can't preview it, even though it still works via a direct --goma-* override. This never affects runtime theming (CSS custom properties still cascade normally): only the interactive theme-preview experience and a few doc cross-references. See the table below for the current state per widget.

Widget-by-widget notes ​

WidgetCategorySeverityFixed?Notes
favoritesTokens/ThemingHighYesCreated src/themeTokens.js and src/styles/favorites.css (previously the package had neither, so it silently rendered core's base theme instead of its documented dark-navy/cyan/amber theme). One token's default (--goma-backgroundSecondary) served two conflicting uses: resolved in favor of the widget's own documented edge-fade behavior; card internals (odds buttons, live tags, borders) intentionally stay on core's shared defaults.
favoritesSizingMediumYesDocumented the missing min-height fallback (doc-only; no sibling-matching fallback added).
suggested-betInitializationHighYesFixed four leaked WAMP subscriptions on transitions a live host makes on a mounted widget: switching dataSource away from rpc/subscribe, replacing the bet with one whose legs carry no eventId, moving the legs to a different sport (subscriptions are keyed per sport, so the old sport's topics stayed open alongside the new one's), and a second rpc resolution after the one-shot snapshot had already fired, which re-subscribed and then never released. Each has a regression test. The driver also stopped re-registering sports it already holds (every re-registration pulls a fresh initial dump over the shared socket) and now releases only the sports that dropped out rather than tearing the whole set down.
filters-settingsSizingHighYesFixed the dead :host{display:inline-block} rule via a local connectedCallback override in the widget's own element class (not a change to the shared createWidgetElement factory): preserves the framework's "host wins" guard for any host-supplied inline style. Added a regression test and a docs sizing note.
filters-settings, competition-filter, region-filter, time-filter, sports-navigation-horizontal, sports-navigation-dialogMisc hygieneHighYesThese six packages carried a ~1.2 MB .size-limit.json budget: a leftover from an early build in which every widget bundle inlined the whole sport-icon registry. The icons have since moved into @gomagaming/core, and the bundles themselves measure 4.3–12.9 kB gzip, so the budget sat ~100x above the real size and no bundle-size regression could trip it. Each budget is now its measured size plus max(5%, 0.5 kB) of headroom. Four further packages (competitions-list, suggested-bet, top-competitions and top-competitions-pills) shared a milder form of the same copy-paste (a flat 30 kB budget over 4.6–12.0 kB bundles, loose rather than unfailable) and were measured at the same time. No widget code changed for any of the ten: the bundles were never actually oversized.
filters-settingsInitializationMediumYesDocumented flagBaseUrl/flag-base-url as declared but currently inert, and added the same note to its custom-elements.json manifest entry.
betslip-sidebarInitializationMediumYesDocs install command now includes the required autobahn-browser peer dependency.
betslip-sidebarTokens/ThemingMediumYesAdded the 7 missing tokens to themeTokens.js.
my-betsTokens/ThemingMediumYesAdded the 4 missing tokens to themeTokens.js.
my-betsInitializationLowYesDocumented flagBaseUrl as currently inert.
my-betsSizingMediumYesDocumented that the min-height:360px floor is not adopted in hosted mode.
game-detailsSizingLowYesAdded a min-height fallback on the widget's root wrapper (matching the mechanism sibling widgets use, an inner-class floor, not a :host-only one).
game-detailsTokens/ThemingMediumYesCorrected themeTokens.js (removed stale backgroundSecondary, added the 6 real tokens).
hero-cardSizingLowYesDocumented the existing min-height:460px fallback.
multi-bannersTokens/ThemingMediumYesAdded the 4 missing tokens to the docs Theming table; removed the unused textSecondary entry from both themeTokens.js and the docs.
missions-hubTokens/ThemingMediumYesCorrected the stale buttonActiveHoverTertiary doc claim (and its source comment); added the missing mission-card tokens to the Theming section.
mission-detailsTokens/ThemingMediumYesCorrected the same stale buttonActiveHoverTertiary doc claim, and a second stale --goma-allWhite claim found while fixing it.
missions-hub / mission-detailsInitializationLowYesDocumented why autobahn-browser is a required peer dependency, matching highlight-card/pros-choice's phrasing.
sports-navigation-dialogTokens/ThemingMediumYesCorrected the doc claim that --goma-iconPrimary drives icon color via <sb-icon> (it doesn't).
competition-filterTokens/ThemingMediumYesAdded the 2 missing tokens to themeTokens.js.
live-chatTokens/ThemingMediumNo: flagged follow-upTwo hardcoded colors bypass theming; source already flags a planned follow-up PR.
live-chatMisc hygieneLowYesAdded theme/config to custom-elements.json's members array with an accurate description of the attribute/property relationship.
region-filterSSR/WebviewLowYesAdded a typeof window !== 'undefined' guard to the sport-picker listener attach/detach, matching the sibling dialog widget's pattern.
sports-navigation-horizontal/dialog/region-filter/competition-filter/time-filterMisc hygieneLowYesThe shared render-error banner's alertError/highlightPrimaryContrast tokens were missing from most of these widgets' Theming tables; added where missing: both on sports-navigation-horizontal, competition-filter and time-filter; alertError only on sports-navigation-dialog (highlightPrimaryContrast was already documented there, for the trigger pill); region-filter already had both and needed no change.
sports-navigation-horizontalMisc hygieneLowYesReworded the stray demo/-referencing comment in playground/mock.js.
events-horizontalMisc hygieneLowYesReworded stray demo/-referencing comments in playground manifest/mock files.
events-horizontalTokens/ThemingMediumYesAdded the 2 missing tokens to themeTokens.js.
top-competitions / top-competitions-pills / competitions-listTokens/ThemingLowYesCorrected each package's themeTokens.js registry.
top-competitions / top-competitions-pills / competitions-listEventsLowYesAdded the missing goma:retry row to each docs page's Events table.
casino-gamesTokens/ThemingLowYesRemoved the unused highlightGradientEnd entry from themeTokens.js.
docs/guide/theming.mdMisc hygieneLowYesAdded filters-settings to the --goma-dialogBackground consumer list; added a new "Betslip" section covering backgroundBetslip/addBetslip/myTickets*/pills.
sports-navigation-dialog (project CLAUDE.md)Misc hygieneLowYesCorrected a stale entry describing manual focus-trap/keydown-tracked-focus code that no longer exists (superseded by the native <dialog> recipe; useFocusTrap is unused repo-wide).
ALL (createWidgetElement-based, 23 widgets) + live-chat + messengerSSR/WebviewHighYesAdded an SSR guard so importing a widget package outside a browser no longer throws: see Cross-cutting caveats.
ALL (23 createWidgetElement-based widgets)InitializationMediumNo: flagged follow-upShared i18n singleton causes cross-widget locale collisions on multi-locale pages: see Cross-cutting caveats.

Known issues being addressed separately ​

  • @gomagaming/core's shared i18n singleton (cross-widget locale collisions on multi-locale pages).
  • live-chat's two hardcoded colors bypassing theming.
  • Event naming/detail-shape parity across sibling widgets.