Skip to content

Theming ​

GomaPulse widgets use CSS custom properties (variables) for all visual styling. Every token is prefixed with --goma- and defined on the :host element inside the Shadow DOM. Because inline styles on :host have the highest specificity, consumer overrides always win.

Quick start ​

js
const el = document.querySelector('goma-events-horizontal')
el.theme = {
  highlightPrimary: '#dc2626',
  backgroundPrimary: '#1a0505',
  buttonBackgroundPrimary: '#dc2626',
}

The widget automatically prepends --goma- to each key, so highlightPrimary becomes --goma-highlightPrimary on the host element. All three key formats are accepted:

Input keyResolved CSS property
highlightPrimary--goma-highlightPrimary
--highlightPrimary--goma-highlightPrimary
--goma-highlightPrimary--goma-highlightPrimary

Using config.theme ​

You can also pass the theme inside the config object:

js
el.config = {
  apiBaseUrl: 'https://api.example.com',
  theme: {
    backgroundPrimary: '#1a0505',
    highlightPrimary: '#dc2626',
  },
}

Both el.theme = {...} and config.theme use the same code path. Setting either one applies the overrides immediately.

Switching themes at runtime (light / dark) ​

Define your light and dark palettes as two plain JavaScript objects with the same set of keys, then assign whichever one you want: the widget reflects the change on the next paint without a remount, a reload, or a class swap. The reactive bridge picks up el.theme = … immediately and writes the values to inline custom properties on the host, so every Vue component that reads var(--goma-…) updates in place.

js
const lightTheme = {
  backgroundPrimary: '#ffffff',
  backgroundSecondary: '#f4f5fb',
  backgroundCards: '#ffffff',
  textPrimary: '#0b0d2a',
  textSecondary: '#5a6280',
  highlightPrimary: '#ff6600',
  buttonBackgroundPrimary: '#ff6600',
  buttonTextPrimary: '#ffffff',
  separatorLine: '#e2e5f0',
  // … cover every token you want to differ between modes
}

const darkTheme = {
  backgroundPrimary: '#03061b',
  backgroundSecondary: '#161732',
  backgroundCards: '#1f2147',
  textPrimary: '#ffffff',
  textSecondary: '#939dff',
  highlightPrimary: '#ff6600',
  buttonBackgroundPrimary: '#ff6600',
  buttonTextPrimary: '#ffffff',
  separatorLine: '#2a2d60',
  // … same keys as lightTheme
}

const el = document.querySelector('goma-events-horizontal')

// Apply light mode
el.theme = lightTheme

// Later: flip to dark mode
el.theme = darkTheme

Reacting to the host's prefers-color-scheme ​

Wire the system preference once and let the watcher swap themes for you:

js
const mql = window.matchMedia('(prefers-color-scheme: dark)')

function syncTheme() {
  el.theme = mql.matches ? darkTheme : lightTheme
}

syncTheme()
mql.addEventListener('change', syncTheme)

One important caveat: keep both objects complete ​

Each el.theme = … call writes the keys of the object you pass; it does not clear keys set by a previous assignment. If lightTheme defines backgroundCards and darkTheme doesn't, the value from lightTheme will linger after the swap.

The safe pattern is to make both objects exhaustive over the tokens you care about. If you must override a single token on top of a base theme, merge explicitly:

js
el.theme = { ...darkTheme, highlightPrimary: '#dc2626' }

Token reference ​

All tokens are defined in src/styles/main.css under the :host block. Each token has a DEFAULT and a -dark variant. Set both for consistent rendering.

Backgrounds ​

TokenCSS variableDefaultDescription
backgroundPrimary--goma-backgroundPrimary#03061bPage / widget background
backgroundSecondary--goma-backgroundSecondary#161732Secondary panels, betslip
backgroundTertiary--goma-backgroundTertiary#1f2147Cards, inputs
backgroundBorder--goma-backgroundBorder#2a2d60Card border backgrounds
backgroundCards--goma-backgroundCards#1f2147Card inner background
backgroundDrop--goma-backgroundDrop#03061bDropdown overlays
backgroundOdds--goma-backgroundOdds#434799Odds button background
backgroundDisabledOdds--goma-backgroundDisabledOdds#2a2d60Suspended odds background
dialogBackground--goma-dialogBackground#03061bModal / dialog panel background: decoupled from backgroundPrimary so a transparent host can still paint an opaque modal. Used by <goma-sports-navigation-dialog>, <goma-betslip-floating>, <goma-filters-settings>, and <goma-my-bets> (cash out dialog).

Text ​

TokenCSS variableDefaultDescription
textPrimary--goma-textPrimary#ffffffPrimary text (team names, labels)
textSecondary--goma-textSecondary#939dffSecondary text (competition, time)
textHeadlinePrimary--goma-textHeadlinePrimary#ffffffHeadline text
textDisablePrimary--goma-textDisablePrimary#434799Disabled / muted text
textOdds--goma-textOdds#ffffffOdds value text
textDisabledOdds--goma-textDisabledOdds#434799Suspended odds text

Icons ​

TokenCSS variableDefaultDescription
iconPrimary--goma-iconPrimary#ffffffPrimary icon fills
iconSecondary--goma-iconSecondary#5559b4Secondary icon fills

Highlights ​

TokenCSS variableDefaultDescription
highlightPrimary--goma-highlightPrimary#ff6600Primary accent (CTA, active states)
highlightSecondary--goma-highlightSecondary#404cffSecondary accent
highlightTertiary--goma-highlightTertiary#01b72eTertiary accent (green)
highlightPrimaryContrast--goma-highlightPrimaryContrast#ffffffText on primary accent
highlightSecondaryContrast--goma-highlightSecondaryContrast#03061bText on secondary accent
highlightGradientStart--goma-highlightGradientStart#29f2ffFeatured-card neon divider: gradient start. Used by <goma-top-competitions> highlighted rows.
highlightGradientEnd--goma-highlightGradientEnd#875affFeatured-card neon divider: gradient end. Used by <goma-top-competitions> highlighted rows.

Separators ​

TokenCSS variableDefaultDescription
separatorLine--goma-separatorLine#2a2d60Divider lines
separatorLineSecondary--goma-separatorLineSecondary#393d83Secondary dividers
scroll--goma-scroll#393d83Scrollbar thumb on a widget's own scrollable region. Painted by <goma-pros-choice>'s odds row when a card carries more outcomes than fit. Shares its default with separatorLineSecondary, but is a separate token so a host can restyle scrollbars without moving every divider on the page.

Buttons ​

TokenCSS variableDefaultDescription
buttonBackgroundPrimary--goma-buttonBackgroundPrimary#ff6600Primary button fill: also the selected odds button background
buttonTextPrimary--goma-buttonTextPrimary#ffffffPrimary button text: also the selected odds button text. Use a colour that reads against buttonBackgroundPrimary (e.g. a dark token on a light accent).
buttonActiveHoverPrimary--goma-buttonActiveHoverPrimary#ff7e29Primary button hover
buttonBackgroundSecondary--goma-buttonBackgroundSecondary#2a2d60Secondary button fill

Live ​

TokenCSS variableDefaultDescription
liveTag--goma-liveTag#ff6600"LIVE" badge background
liveBorder1--goma-liveBorder1#ff6000Live card border gradient stop 1
liveBorder2--goma-liveBorder2#ff934cLive card border gradient stop 2
liveBorder3--goma-liveBorder3#7a83ffLive card border gradient stop 3
liveShadowColor--goma-liveShadowColorrgba(235, 92, 104, 1)Live badge drop shadow

Live-count badge (sports-navigation) ​

Used by <goma-sports-navigation-horizontal> for the small pill on the top-right of each sport tile that has numberOfLiveEvents > 0.

TokenCSS variableDefaultDescription
liveCountBackground--goma-liveCountBackground#ed4f63Pill background
liveCountText--goma-liveCountText#ffffffNumber colour

Both have -dark variants. The badge wraps a 2px --goma-backgroundPrimary ring around the pill so it pops cleanly off the surrounding circle.

Odds-update flash (RegularOdds) ​

When odds tick up or down on a <RegularOdds> button, the card temporarily highlights with a coloured border + arrow icon. The background during that highlight is controlled by the two tokens below; both default to the resting --goma-backgroundOdds so the card doesn't flash by default: that matches the betsson-france baseline where the only visual cue is the border and the up/down arrow.

TokenCSS variableDefaultDescription
oddsUpdateUp--goma-oddsUpdateUpvar(--goma-backgroundOdds)Card background while odds are flashing up
oddsUpdateDown--goma-oddsUpdateDownvar(--goma-backgroundOdds)Card background while odds are flashing down
oddsUpdateUpBorder--goma-oddsUpdateUpBorder#21ba452 px border + ▲ arrow colour while odds are flashing up
oddsUpdateDownBorder--goma-oddsUpdateDownBorder#ed4f632 px border + ▼ arrow colour while odds are flashing down

All four have -dark variants. The borders + arrow inherit the alertSuccess / alertError palette by default so the price-change cue stays vibrant against the resting card. The fill stays unchanged unless a theme overrides oddsUpdateUp / oddsUpdateDown.

Alerts ​

TokenCSS variableDefaultDescription
alertError--goma-alertError#ed4f63Error state
alertSuccess--goma-alertSuccess#21ba45Success state
alertWarning--goma-alertWarning#f2c037Warning state

Betslip ​

Shared by <goma-betslip-floating>, <goma-betslip-sidebar>, and <goma-my-bets> (the embedded My Bets tab and the standalone widget alike). Each widget's own :host stylesheet layers its own default palette on top of these core values: see each widget's docs page for what actually renders by default in that widget.

TokenCSS variableDefaultDescription
backgroundBetslip--goma-backgroundBetslip#161732Betslip panel / selections-body surface
addBetslip--goma-addBetslip#939dffQuick-add stake chips
myTicketsWon--goma-myTicketsWon#0f5531Won bet status strip / footer tint
myTicketsLost--goma-myTicketsLost#60111bLost bet status strip / footer tint
myTicketsOther--goma-myTicketsOther#946f00Void / cashed-out bet status strip / footer tint

pills (--goma-pills, My Bets' Open / Closed / Won sub-tab row) is the same global token documented under Missions: see that section for its default and description.

<goma-betslip-floating> and <goma-betslip-sidebar> also read five optional tokens. None has a default of its own: unset, each falls back to the shared token it painted before, so a host only sets them to restyle that one surface.

TokenCSS variableFalls back toDescription
stakeInputBackground--goma-stakeInputBackground--goma-backgroundPrimaryEvery stake input's fill
stakeInputBorder--goma-stakeInputBorder--goma-separatorLineEvery stake input's border
betslipTabText--goma-betslipTabText--goma-textSecondaryInactive panel-tab labels (Betslip / My Bets)
betslipRadioDot--goma-betslipRadioDot--goma-textPrimarySelected settings-radio centre
betslipRadioBorder--goma-betslipRadioBorder--goma-textSecondary at 60%Unselected radio rings (settings and bonus picker)

Stake-row sizes are structure, not colour: they are appearance keys on both betslip elements.

Cards ​

TokenCSS variableDefaultDescription
cardBorderLineGradient1--goma-cardBorderLineGradient1#393d83Card border gradient stop 1
cardBorderLineGradient2--goma-cardBorderLineGradient2#7c4b57Card border gradient stop 2
secondaryCardBorder--goma-secondaryCardBorderfalls back to --goma-cardBorderLineGradient2Optional: the flat 1px frame of the secondary (additional-market, pre-live and outright) cards. Unset, the frame is cardBorderLineGradient2, as before; set it to frame those cards without moving the main card's gradient mid-stop.
cardBorderLineGradient3--goma-cardBorderLineGradient3#b25633Card border gradient stop 3

<goma-casino-games>, <goma-multi-banners> and <goma-sports-navigation-horizontal> share one arrow: an allWhite disc at 60% with a highlightSecondaryContrast caret. Two optional tokens override it for a palette where those do not pair (e.g. a light theme that wants a dark disc):

TokenCSS variableFalls back toDescription
navArrowBackground--goma-navArrowBackground--goma-allWhite at 60%Arrow disc (applied where the engine supports color-mix(); elsewhere the disc stays the 60% white)
navArrowIcon--goma-navArrowIcon--goma-highlightSecondaryContrastArrow caret

Game details (market tabs + cards) ​

<goma-game-details> mostly reuses the shared token set, but its market-category tab pills read two widget-specific tokens. Neither has a default of its own: unset, each falls back to the shared token below, so a host only sets them to restyle the tabs without recolouring the market cards.

TokenCSS variableFalls back toDescription
tabPillBackground--goma-tabPillBackground--goma-backgroundCardsMarket-category tab pill: background (idle and active)
tabPillText--goma-tabPillText--goma-textSecondaryTab pill text: idle

The active pill keeps a --goma-highlightPrimary border and a --goma-textPrimary label. The Tailwind preset also defines tabPillBackgroundActive, tabPillTextActive and marketCardHeaderBackground, but no component reads them yet.

The other notable surfaces map to shared tokens:

SurfaceToken(s)
Page background--goma-backgroundPrimary
Header background--goma-backgroundSecondary
LIVE badge + clock--goma-liveTag, --goma-liveBorder1 / 2 / 3
Market card gradient border--goma-cardBorderLineGradient1 / 2 / 3
Market card body--goma-backgroundCards
Odds value text--goma-textOdds

Miscellaneous ​

TokenCSS variableDefaultDescription
favorites--goma-favorites#fac125Favorite star colour
statsHome--goma-statsHome#d99f00Home team stats
statsAway--goma-statsAway#46c1a7Away team stats

Typography & Shape ​

TokenCSS variableDefaultDescription
fontFamily--goma-fontFamily'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serifBase font stack
fontSize--goma-fontSize13pxBase font size
scoreRadius--goma-scoreRadius4pxScore box border radius

Widget gutter ​

Some widgets draw their content flush to the edge of the element and others add horizontal padding of their own, so stacking them in a column starts their content at different offsets and the page has to cancel the difference with negative margins.

--goma-widgetInset is the single knob that settles it. Set it once (on the page, or on an individual widget) and every edge-to-edge widget adopts the same gutter. It is an ordinary theme token, so all three of the usual routes work:

css
/* Page-wide, in your own stylesheet. */
:root {
  --goma-widgetInset: 0;
}
js
// Per widget, through config.theme like any other token.
el.config = { theme: { widgetInset: '0' } }
html
<!-- Per widget, inline. -->
<goma-casino-games style="--goma-widgetInset: 0"></goma-casino-games>
TokenCSS variableDefaultDescription
widgetInset--goma-widgetInsetper widget, see belowHorizontal gutter between a widget's content and the edge of the element

Horizontal only

The token sets inline (left/right) padding and nothing else. Vertical padding is the space between sections, which your own layout already controls with margins: folding it into the same token would mean setting the gutter to 8px silently added 8px of top padding to rails that had none.

There is deliberately no global default. Leaving the token unset keeps each widget exactly as it renders today, so adopting it is opt-in and nothing moves until you ask:

WidgetGutter when the token is unset
<goma-multi-banners>8px
<goma-casino-games>8px
<goma-sports-navigation-horizontal>0

Every other widget runs flush already and is unaffected: the token does not add padding to a widget that has none.

Panel widgets are not governed by it. <goma-competitions-list> and <goma-top-competitions> (list variant) paint a rounded panel and keep a fixed 16px interior. That padding is the inside of a box the widget draws, not a page gutter: zeroing it would put their rows and separator lines against their own edge. If you want those flush to the page, give the widget a transparent background instead.

Custom properties inherit

Setting the token on :root reaches every widget on the page. Usually what you want, but it means you cannot set a page-wide value and expect one widget to keep its own. Give that widget an explicit override instead:

css
:root { --goma-widgetInset: 0; }
goma-multi-banners { --goma-widgetInset: 8px; }

Missions (hub + details) ​

Used by <goma-missions-hub> and <goma-mission-details> to restyle tab pills, cards, buttons and the level/reward/requirement surfaces for light-theme host parity. The token set is split by how a host supplies it:

  • Colour tokens (below) need light/dark pairs, so they are set through config.theme (el.theme = { pills: '…', missionButtonBg: '…' }) exactly like every other --goma-* colour token on this page.
  • Geometry / structure tokens (radii, border widths, pill typography and size) are mode-agnostic single values, so they are exposed through the widgets' curated appearance object: set via el.appearance = {...}. They are still plain --goma-* tokens and can be set through theme too, but appearance is the documented door.

The same appearance door exists on other widgets, each with its own curated keys and defaults that reproduce the current look: <goma-betslip-sidebar> / <goma-betslip-floating> (stake row), <goma-competition-filter> (pill height, sides, ring, bar padding), <goma-top-competitions-pills> (pill geometry, flag size), <goma-time-filter> (readout size), <goma-multi-banners> (rail padding, card type sizes, CTA button, dot gap) and <goma-casino-games> (pagination dots).

The defaults reproduce the dark "Pulse" look. Some tokens only affect one of the two widgets: the pill tokens and radiusCard style the hub's pill strip and mission cards but are no-ops on <goma-mission-details> (underline tabs, fixed-radius cards); the missionRewardIcon / missionRequirementIcon glyphs and every missionLevel* token are the mirror case. They style <goma-mission-details>'s Levels tab and are no-ops on the hub (which shows reward/requirement as text). missionHistoryWonColor is hub-only (the Finished-tab history card).

Colour tokens (set via config.theme):

TokenCSS variableDefaultAffects
pillBg--goma-pillBgvar(--goma-pills)Inactive tab-pill background (role token). pills (#2a2d60) is the palette token it defaults to.
pillText--goma-pillText#ffffffInactive tab-pill text
pillActiveBg--goma-pillActiveBg#2a2d60Active tab-pill fill
pillActiveText--goma-pillActiveText#ffffffActive tab-pill text
pillActiveBorderColor--goma-pillActiveBorderColorvar(--goma-highlightPrimary)Active tab-pill ring colour
pillActiveRing--goma-pillActiveRing(none, a flat sheet of pillActiveBorderColor)What the active tab-pill's ring is painted with. Accepts any CSS <image>, so the ring can be a gradient instead of a flat colour. See Giving the active tab pill a gradient ring.
missionButtonBg--goma-missionButtonBgvar(--goma-allWhite)Filled CTA button background
missionButtonText--goma-missionButtonTextvar(--goma-allDark)Filled CTA button text
missionButtonBorderColor--goma-missionButtonBorderColorvar(--goma-allWhite)Outline CTA button border/text
missionRewardIcon--goma-missionRewardIconvar(--goma-highlightSecondary)Reward (gift) glyph: mission-details Levels tab only
missionRequirementIcon--goma-missionRequirementIcon#ffd064Requirement (sword) glyph: mission-details Levels tab only
stickyFooterOffset--goma-stickyFooterOffset(none, behaves as 0px)Distance the mission-details CTA is lifted off the viewport bottom. Set it to the height of your own fixed bottom chrome (nav bar, cookie bar) so the CTA is not covered.
stickyFooterZIndex--goma-stickyFooterZIndex(none, behaves as auto)Stacking order of that same CTA. Raise it above your fixed chrome's z-index when lifting the footer is not enough on its own.
missionTagBg--goma-missionTagBg(none, the pill paints a missionTagBgStart to missionTagBgEnd gradient; both default to var(--goma-backgroundSecondary), so the pill is flat)Banner type tag (Sports/Casino) background
missionTagBorderColor--goma-missionTagBorderColorvar(--goma-highlightTertiary)Banner type tag border
missionUnlockText--goma-missionUnlockTextvar(--goma-highlightTertiary)Card unlock/description line
missionValueText--goma-missionValueTextvar(--goma-highlightTertiary)Card values (levels / requirement / reward / min-deposit)
missionLevelBadgeBg--goma-missionLevelBadgeBgvar(--goma-highlightTertiary)Level-number progress badge fill
missionLevelBadgeBorderColor--goma-missionLevelBadgeBorderColortransparentLevel-number badge ring
missionLevelBadgeText--goma-missionLevelBadgeTextvar(--goma-textPrimary)Level-number badge text
missionLevelActiveBorderStart--goma-missionLevelActiveBorderStartvar(--goma-highlightTertiary)Detail Levels-tab active card gradient border start
missionLevelActiveBorderEnd--goma-missionLevelActiveBorderEndvar(--goma-highlightSecondary)Detail Levels-tab active card gradient border end
missionLevelCompletedBorderColor--goma-missionLevelCompletedBorderColorvar(--goma-highlightSecondary)Detail Levels-tab completed card border
missionHistoryWonColor--goma-missionHistoryWonColorvar(--goma-highlightTertiary)Finished-tab history card won/completed accent (TOTAL WON summary border + value + trophy, completed level badge + reward + "Completed" label). Forfeited rows keep --goma-alertError.

Role tokens and layout keys. The Challenges widgets also read these role tokens, each with a -dark twin. They are listed with their defaults and when to set them in the Theming sections of <goma-missions-hub> and <goma-mission-details>. This page does not repeat those tables.

  • Role tokens: pillBg, pillActiveText, pillActiveBg, missionButtonBg, missionButtonText, missionButtonBorderColor, missionCtaOutlineText, missionDetailTabIndicator, missionDetailTabTrack, missionTopTabTrack, missionTopTabInactiveLine, missionDetailTabActiveText, missionUnlockText, missionValueText, missionHeaderUnlockText, missionRulesTermsLink, missionTermsLink, missionProgressFillStart, missionEventsPercent, missionEventsPercentComplete, missionLevelCompletedText, missionHubBg, missionDetailsBg, missionPillsBarBg, missionTagBgStart, missionTagBgEnd.
  • Appearance keys (see the same sections for the accepted values): gamesColumns, gameTileRatio, detailTabsFullWidth, detailTabIndicatorHeight, topTabIndicatorHeight, pillsBarPaddingBottom and fontFamily.

Geometry / structure tokens (set via el.appearance, mode-agnostic):

TokenCSS variableDefaultDescription
radiusCard--goma-radiusCard(none, per-card fallback)Hub mission-card corner radius, all card types (appearance.cardRadius). No :host default: challenger cards fall back to 0.5rem, Finished history cards to 20px, so setting it overrides both.
radiusButton--goma-radiusButton9999pxCTA button corner radius (appearance.buttonRadius)
radiusPill--goma-radiusPill9999pxTab-pill corner radius (appearance.pillRadius)
missionLevelCardRadius--goma-missionLevelCardRadius20pxDetail Levels-tab card corner radius (appearance.levelCardRadius)
pillActiveBorderWidth--goma-pillActiveBorderWidth2pxActive tab-pill ring width; 0 → solid fill (appearance.pillActiveBorderWidth)
pillFontWeight--goma-pillFontWeight700Inactive tab-pill font weight (appearance.pillFontWeight)
pillActiveFontWeight--goma-pillActiveFontWeight700Active tab-pill font weight (appearance.pillActiveFontWeight)
pillHeight--goma-pillHeight40pxTab-pill height (appearance.pillHeight)
pillPaddingX--goma-pillPaddingX16pxTab-pill horizontal padding (appearance.pillPaddingX)

Giving the active tab pill a gradient ring ​

The selected Active / Pending / Finished pill wears a ring. By default that ring is a flat colour (pillActiveBorderColor, at pillActiveBorderWidth) which is what most themes want.

Some designs sweep the ring through more than one colour. A CSS border only accepts a colour, never a gradient, so the widget paints the ring as a background layer instead and exposes what it is painted with as pillActiveRing. It takes any CSS <image>:

css
goma-missions-hub {
  --goma-pillActiveRing: conic-gradient(
    from 180deg,
    #343641 11%,
    #aa1323 66%,
    #343641
  );
}

Or through config.theme, which is where it belongs: the ring is a paint, so it travels with the colours, while its width is structure and stays in appearance:

js
el.theme = {
  pillActiveRing: 'conic-gradient(from 180deg, #343641 11%, #aa1323 66%, #343641)',
}
el.appearance = { pillActiveBorderWidth: '2px' }

Three things worth knowing:

  • Repeat your first colour as the last stop. A conic gradient wraps from 360° back to 0°, and two different colours meeting there leave a visible seam down one side of the pill.
  • pillActiveBorderWidth still controls the thickness, and 0 still collapses the ring entirely, leaving a plain pillActiveBg fill. The two tokens compose.
  • Leave pillActiveRing unset and nothing changes. It falls back to a flat sheet of pillActiveBorderColor, which renders identically to the solid border it replaced.

Embedding examples ​

Vanilla HTML ​

html
<goma-events-horizontal id="sb"></goma-events-horizontal>
<script type="module">
  import '@gomagaming/events-horizontal'

  const el = document.getElementById('sb')
  el.config = { apiBaseUrl: 'https://api.example.com' }
  el.theme = { highlightPrimary: '#dc2626', backgroundPrimary: '#1a0505' }
</script>

React ​

jsx
import '@gomagaming/events-horizontal'

function Feed({ config }) {
  return (
    <goma-events-horizontal
      ref={(el) => {
        if (!el) return
        el.config = config
        el.theme = { highlightPrimary: '#dc2626' }
      }}
    />
  )
}

Vue 3 ​

vue
<script setup>
import '@gomagaming/events-horizontal'
import { ref, onMounted } from 'vue'

const el = ref(null)
onMounted(() => {
  el.value.config = { apiBaseUrl: 'https://api.example.com' }
  el.value.theme = { highlightPrimary: '#dc2626' }
})
</script>

<template>
  <goma-events-horizontal ref="el" />
</template>

Full theme example ​

A complete red theme:

js
el.theme = {
  backgroundPrimary: '#1a0505',
  'backgroundPrimary-dark': '#1a0505',
  backgroundSecondary: '#2d0a0a',
  'backgroundSecondary-dark': '#2d0a0a',
  backgroundCards: '#3d1212',
  'backgroundCards-dark': '#3d1212',
  backgroundOdds: '#5c1a1a',
  'backgroundOdds-dark': '#5c1a1a',
  highlightPrimary: '#dc2626',
  'highlightPrimary-dark': '#dc2626',
  buttonBackgroundPrimary: '#dc2626',
  'buttonBackgroundPrimary-dark': '#dc2626',
  liveBorder1: '#dc2626',
  'liveBorder1-dark': '#dc2626',
  liveShadowColor: 'rgba(220, 38, 38, 0.8)',
  cardBorderLineGradient1: '#5c1a1a',
  cardBorderLineGradient2: '#8b2020',
  cardBorderLineGradient3: '#dc2626',
}