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 key | Resolved 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 = darkThemeReacting 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
| Token | CSS variable | Default | Description |
|---|---|---|---|
backgroundPrimary | --goma-backgroundPrimary | #03061b | Page / widget background |
backgroundSecondary | --goma-backgroundSecondary | #161732 | Secondary panels, betslip |
backgroundTertiary | --goma-backgroundTertiary | #1f2147 | Cards, inputs |
backgroundBorder | --goma-backgroundBorder | #2a2d60 | Card border backgrounds |
backgroundCards | --goma-backgroundCards | #1f2147 | Card inner background |
backgroundDrop | --goma-backgroundDrop | #03061b | Dropdown overlays |
backgroundOdds | --goma-backgroundOdds | #434799 | Odds button background |
backgroundDisabledOdds | --goma-backgroundDisabledOdds | #2a2d60 | Suspended odds background |
dialogBackground | --goma-dialogBackground | #03061b | Modal / 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
| Token | CSS variable | Default | Description |
|---|---|---|---|
textPrimary | --goma-textPrimary | #ffffff | Primary text (team names, labels) |
textSecondary | --goma-textSecondary | #939dff | Secondary text (competition, time) |
textHeadlinePrimary | --goma-textHeadlinePrimary | #ffffff | Headline text |
textDisablePrimary | --goma-textDisablePrimary | #434799 | Disabled / muted text |
textOdds | --goma-textOdds | #ffffff | Odds value text |
textDisabledOdds | --goma-textDisabledOdds | #434799 | Suspended odds text |
Icons
| Token | CSS variable | Default | Description |
|---|---|---|---|
iconPrimary | --goma-iconPrimary | #ffffff | Primary icon fills |
iconSecondary | --goma-iconSecondary | #5559b4 | Secondary icon fills |
Highlights
| Token | CSS variable | Default | Description |
|---|---|---|---|
highlightPrimary | --goma-highlightPrimary | #ff6600 | Primary accent (CTA, active states) |
highlightSecondary | --goma-highlightSecondary | #404cff | Secondary accent |
highlightTertiary | --goma-highlightTertiary | #01b72e | Tertiary accent (green) |
highlightPrimaryContrast | --goma-highlightPrimaryContrast | #ffffff | Text on primary accent |
highlightSecondaryContrast | --goma-highlightSecondaryContrast | #03061b | Text on secondary accent |
highlightGradientStart | --goma-highlightGradientStart | #29f2ff | Featured-card neon divider: gradient start. Used by <goma-top-competitions> highlighted rows. |
highlightGradientEnd | --goma-highlightGradientEnd | #875aff | Featured-card neon divider: gradient end. Used by <goma-top-competitions> highlighted rows. |
Separators
| Token | CSS variable | Default | Description |
|---|---|---|---|
separatorLine | --goma-separatorLine | #2a2d60 | Divider lines |
separatorLineSecondary | --goma-separatorLineSecondary | #393d83 | Secondary dividers |
scroll | --goma-scroll | #393d83 | Scrollbar 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
| Token | CSS variable | Default | Description |
|---|---|---|---|
buttonBackgroundPrimary | --goma-buttonBackgroundPrimary | #ff6600 | Primary button fill: also the selected odds button background |
buttonTextPrimary | --goma-buttonTextPrimary | #ffffff | Primary 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 | #ff7e29 | Primary button hover |
buttonBackgroundSecondary | --goma-buttonBackgroundSecondary | #2a2d60 | Secondary button fill |
Live
| Token | CSS variable | Default | Description |
|---|---|---|---|
liveTag | --goma-liveTag | #ff6600 | "LIVE" badge background |
liveBorder1 | --goma-liveBorder1 | #ff6000 | Live card border gradient stop 1 |
liveBorder2 | --goma-liveBorder2 | #ff934c | Live card border gradient stop 2 |
liveBorder3 | --goma-liveBorder3 | #7a83ff | Live card border gradient stop 3 |
liveShadowColor | --goma-liveShadowColor | rgba(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.
| Token | CSS variable | Default | Description |
|---|---|---|---|
liveCountBackground | --goma-liveCountBackground | #ed4f63 | Pill background |
liveCountText | --goma-liveCountText | #ffffff | Number 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.
| Token | CSS variable | Default | Description |
|---|---|---|---|
oddsUpdateUp | --goma-oddsUpdateUp | var(--goma-backgroundOdds) | Card background while odds are flashing up |
oddsUpdateDown | --goma-oddsUpdateDown | var(--goma-backgroundOdds) | Card background while odds are flashing down |
oddsUpdateUpBorder | --goma-oddsUpdateUpBorder | #21ba45 | 2 px border + ▲ arrow colour while odds are flashing up |
oddsUpdateDownBorder | --goma-oddsUpdateDownBorder | #ed4f63 | 2 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
| Token | CSS variable | Default | Description |
|---|---|---|---|
alertError | --goma-alertError | #ed4f63 | Error state |
alertSuccess | --goma-alertSuccess | #21ba45 | Success state |
alertWarning | --goma-alertWarning | #f2c037 | Warning 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.
| Token | CSS variable | Default | Description |
|---|---|---|---|
backgroundBetslip | --goma-backgroundBetslip | #161732 | Betslip panel / selections-body surface |
addBetslip | --goma-addBetslip | #939dff | Quick-add stake chips |
myTicketsWon | --goma-myTicketsWon | #0f5531 | Won bet status strip / footer tint |
myTicketsLost | --goma-myTicketsLost | #60111b | Lost bet status strip / footer tint |
myTicketsOther | --goma-myTicketsOther | #946f00 | Void / 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.
| Token | CSS variable | Falls back to | Description |
|---|---|---|---|
stakeInputBackground | --goma-stakeInputBackground | --goma-backgroundPrimary | Every stake input's fill |
stakeInputBorder | --goma-stakeInputBorder | --goma-separatorLine | Every stake input's border |
betslipTabText | --goma-betslipTabText | --goma-textSecondary | Inactive panel-tab labels (Betslip / My Bets) |
betslipRadioDot | --goma-betslipRadioDot | --goma-textPrimary | Selected 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
| Token | CSS variable | Default | Description |
|---|---|---|---|
cardBorderLineGradient1 | --goma-cardBorderLineGradient1 | #393d83 | Card border gradient stop 1 |
cardBorderLineGradient2 | --goma-cardBorderLineGradient2 | #7c4b57 | Card border gradient stop 2 |
secondaryCardBorder | --goma-secondaryCardBorder | falls back to --goma-cardBorderLineGradient2 | Optional: 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 | #b25633 | Card border gradient stop 3 |
Carousel navigation arrow
<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):
| Token | CSS variable | Falls back to | Description |
|---|---|---|---|
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-highlightSecondaryContrast | Arrow 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.
| Token | CSS variable | Falls back to | Description |
|---|---|---|---|
tabPillBackground | --goma-tabPillBackground | --goma-backgroundCards | Market-category tab pill: background (idle and active) |
tabPillText | --goma-tabPillText | --goma-textSecondary | Tab 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:
| Surface | Token(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
| Token | CSS variable | Default | Description |
|---|---|---|---|
favorites | --goma-favorites | #fac125 | Favorite star colour |
statsHome | --goma-statsHome | #d99f00 | Home team stats |
statsAway | --goma-statsAway | #46c1a7 | Away team stats |
Typography & Shape
| Token | CSS variable | Default | Description |
|---|---|---|---|
fontFamily | --goma-fontFamily | 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif | Base font stack |
fontSize | --goma-fontSize | 13px | Base font size |
scoreRadius | --goma-scoreRadius | 4px | Score 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>| Token | CSS variable | Default | Description |
|---|---|---|---|
widgetInset | --goma-widgetInset | per widget, see below | Horizontal 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:
| Widget | Gutter 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
appearanceobject: set viael.appearance = {...}. They are still plain--goma-*tokens and can be set throughthemetoo, butappearanceis 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):
| Token | CSS variable | Default | Affects |
|---|---|---|---|
pillBg | --goma-pillBg | var(--goma-pills) | Inactive tab-pill background (role token). pills (#2a2d60) is the palette token it defaults to. |
pillText | --goma-pillText | #ffffff | Inactive tab-pill text |
pillActiveBg | --goma-pillActiveBg | #2a2d60 | Active tab-pill fill |
pillActiveText | --goma-pillActiveText | #ffffff | Active tab-pill text |
pillActiveBorderColor | --goma-pillActiveBorderColor | var(--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-missionButtonBg | var(--goma-allWhite) | Filled CTA button background |
missionButtonText | --goma-missionButtonText | var(--goma-allDark) | Filled CTA button text |
missionButtonBorderColor | --goma-missionButtonBorderColor | var(--goma-allWhite) | Outline CTA button border/text |
missionRewardIcon | --goma-missionRewardIcon | var(--goma-highlightSecondary) | Reward (gift) glyph: mission-details Levels tab only |
missionRequirementIcon | --goma-missionRequirementIcon | #ffd064 | Requirement (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-missionTagBorderColor | var(--goma-highlightTertiary) | Banner type tag border |
missionUnlockText | --goma-missionUnlockText | var(--goma-highlightTertiary) | Card unlock/description line |
missionValueText | --goma-missionValueText | var(--goma-highlightTertiary) | Card values (levels / requirement / reward / min-deposit) |
missionLevelBadgeBg | --goma-missionLevelBadgeBg | var(--goma-highlightTertiary) | Level-number progress badge fill |
missionLevelBadgeBorderColor | --goma-missionLevelBadgeBorderColor | transparent | Level-number badge ring |
missionLevelBadgeText | --goma-missionLevelBadgeText | var(--goma-textPrimary) | Level-number badge text |
missionLevelActiveBorderStart | --goma-missionLevelActiveBorderStart | var(--goma-highlightTertiary) | Detail Levels-tab active card gradient border start |
missionLevelActiveBorderEnd | --goma-missionLevelActiveBorderEnd | var(--goma-highlightSecondary) | Detail Levels-tab active card gradient border end |
missionLevelCompletedBorderColor | --goma-missionLevelCompletedBorderColor | var(--goma-highlightSecondary) | Detail Levels-tab completed card border |
missionHistoryWonColor | --goma-missionHistoryWonColor | var(--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,pillsBarPaddingBottomandfontFamily.
Geometry / structure tokens (set via el.appearance, mode-agnostic):
| Token | CSS variable | Default | Description |
|---|---|---|---|
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-radiusButton | 9999px | CTA button corner radius (appearance.buttonRadius) |
radiusPill | --goma-radiusPill | 9999px | Tab-pill corner radius (appearance.pillRadius) |
missionLevelCardRadius | --goma-missionLevelCardRadius | 20px | Detail Levels-tab card corner radius (appearance.levelCardRadius) |
pillActiveBorderWidth | --goma-pillActiveBorderWidth | 2px | Active tab-pill ring width; 0 → solid fill (appearance.pillActiveBorderWidth) |
pillFontWeight | --goma-pillFontWeight | 700 | Inactive tab-pill font weight (appearance.pillFontWeight) |
pillActiveFontWeight | --goma-pillActiveFontWeight | 700 | Active tab-pill font weight (appearance.pillActiveFontWeight) |
pillHeight | --goma-pillHeight | 40px | Tab-pill height (appearance.pillHeight) |
pillPaddingX | --goma-pillPaddingX | 16px | Tab-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.
pillActiveBorderWidthstill controls the thickness, and0still collapses the ring entirely, leaving a plainpillActiveBgfill. The two tokens compose.- Leave
pillActiveRingunset and nothing changes. It falls back to a flat sheet ofpillActiveBorderColor, 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',
}