Event Card
A single-event card with compact/standard/hero templates, team + tennis scoring, sport-aware status labels, live auto-refresh, optional detail tabs, and optional single predictions.
A single-event card — a competition header over the two competitors and their kickoff time, live score, or final result. Team sports show one score column; tennis shows a per-set breakdown with an expandable scoreboard. Live events auto-refresh. Sport-agnostic: it adapts its status labels and score layout to whichever sport the Sports API returns (football, basketball, tennis, ice hockey, American football, …). With data-event-card-type="detailed" the same card grows a tab strip below the header — form and streaks, the match timeline, stats, lineups, standings and head-to-head. Football events can additionally let signed-in users place predictions across several markets.
No authentication required — unless you configure the prediction attributes below. Without them, this widget never needstokenString,tokenCookieName, orfirebase. Configuring predictions re-enables the normal Authentication Hierarchy, since submitting one needs a real signed-in identity. See Getting Started → Authentication → Read-only widgets.
<div data-component="fu-widget" data-content-type="event-card" data-content-id="fb:m:12345"></div>Configuration Attributes
| Attribute | Description | Options/Format | Default |
|---|---|---|---|
data-content-id | Event ID | e.g. "fb:m:12345" | Required |
data-event-card-template | Visual density of the card | "compact", "standard", "hero" | "standard" |
data-event-card-type | Kind of card. "detailed" adds the detail tab strip below the header | "header", "detailed" | "header" |
data-event-card-show-competition | Show the competition header above the competitors | "true", "false" | true |
data-event-card-show-form | "detailed" only. Show the Preview tab (form, streaks, latest results) | "true", "false" | true |
data-event-card-show-timeline | "detailed" only. Show the Summary tab (main-events timeline) | "true", "false" | true |
data-event-card-show-stats | "detailed" only. Show the Stats tab | "true", "false" | true |
data-event-card-show-lineups | "detailed" only. Show the Lineups tab | "true", "false" | true |
data-event-card-show-standings | "detailed" only. Show the Table (standings) tab | "true", "false" | true |
data-event-card-show-head-to-head | "detailed" only. Show the H2H tab | "true", "false" | true |
data-event-card-default-section | "detailed" only. Which tab opens first | "preview", "summary", "stats", "lineups", "table", "h2h" | First tab of the event's status |
data-event-card-show-odds | Render betting odds under the scoreboard of an upcoming or live event — see Betting Odds | "true", "false" | false |
data-event-card-odds-market | The market to show | See Odds Widget → Markets | "FT_1X2" |
data-event-card-odds-mode | "flash" alternates the operator logo and the prices instead of showing both | "default", "flash" | "flash" on compact, "default" otherwise |
data-event-card-odds-flash-interval | Flash interval in milliseconds. Ignored unless the mode is "flash" | Positive integer | 3000 |
data-event-card-odds-polling-interval | Odds poll interval in milliseconds | Positive integer | 30000 |
data-event-card-odds-operators | Comma-separated operator config ids, in preference order — the card shows one operator, the first with a complete market | e.g. "betano-bg,efbet-bg" | First operator with prices |
data-event-card-odds-affiliate-id | Affiliate id substituted into every operator URL carrying an {affiliate_id} placeholder | Affiliate id string | None |
data-event-card-odds-affiliate-ids | JSON object of per-operator affiliate ids. Wins over data-event-card-odds-affiliate-id | e.g. '{"betano-bg":"aff-123"}' | None |
data-event-card-operator-id | Deprecated — use data-event-card-odds-operators. Still honoured when that is unset | Operator config id, e.g. "betano-bg" | None |
data-event-card-add-to-betslip | Push a clicked odds price into the Betslip widget on the page | "true", "false" | false |
data-event-card-live-refresh | Poll the events API while the event is LIVE so scores/status stay current | "true", "false" | true |
data-event-card-refresh-interval | Live-refresh poll interval in milliseconds. Only applies while LIVE | Positive integer | 30000 (30s) |
Prediction attributes:
| Attribute | Description | Options/Format | Default |
|---|---|---|---|
data-event-card-predictions-markets | Comma-separated markets to offer, in display order. Omit for no prediction UI | e.g. "FT_1X2,CORRECT_SCORE_ADVANCED" | None |
data-event-card-predictions-display | Markets behind a collapsible footer row, or rendered directly | "drawer", "inline" | "drawer" |
data-event-card-predictions-cutoff-minutes | Minutes before kickoff when predictions close. 15 is also the minimum | Integer ≥ 15 | 15 |
data-event-card-predictions-allow-delete | Let users remove a prediction they already made | "true", "false" | true |
data-event-card-predictions-default-expanded | Start the drawer expanded. Only applies to "drawer" | "true", "false" | false |
data-event-card-predictions-show-summary | Also show how the whole audience predicted each market | "true", "false" | false |
Templates
data-event-card-template picks the visual prominence of the same card — it does not change what data is shown.
| Value | Layout |
|---|---|
"compact" | Livescore-style row: time/status on the left, competitors stacked on the right with a single score column (team sports) or per-set grid (tennis) |
"standard" (default) | Competitors flank a central kickoff time / score, each crest beside its name |
"hero" | Large card — crest stacked over each name, score/time centered in an inset panel with a live accent bar |
<div data-component="fu-widget" data-content-type="event-card" data-content-id="fb:m:12345" data-event-card-template="hero"></div>Card Type
| Value | Behavior |
|---|---|
"header" (default) | The condensed event card (competition header + competitors + time/score) and nothing else |
"detailed" | The same header card, plus a tab strip of detail panels below it — see below |
data-event-card-type and data-event-card-template are independent: every template renders both types.
Detailed Card
data-event-card-type="detailed" keeps the header card exactly as it is and adds a tab strip below it, at no extra request — the single-event endpoint already returns form, season stats, standings and head-to-head alongside the event, so the type only decides whether the strip is rendered from data already in hand. With predictions configured as well, the prediction drawer sits directly under the header and the detail tabs below it.
<div data-component="fu-widget" data-content-type="event-card" data-content-id="fb:m:12345" data-event-card-type="detailed"></div>The event's status picks the candidate tabs — UPCOMING: Preview · Stats · Table · H2H; started (LIVE / FINISHED / CANCELLED): Summary · Stats · Lineups · Table · H2H. Each candidate then has to survive two checks: its attribute is not "false", and the payload carries data for it.
| Tab | Attribute | Shows | Hidden when |
|---|---|---|---|
| Preview | data-event-card-show-form | Form filter (overall / home / away / in competition) over W-D-L dots, a streaks grid, and each side's latest results | Set to "false", or neither side has form data |
| Summary | data-event-card-show-timeline | The main-events timeline — minute, home events left of a centre score column, away right. Goals highlighted with the running score, HT/FT markers, own goals and VAR-disallowed tagged, substitutions headlined by the player coming on | Set to "false", or no main events yet |
| Stats | data-event-card-show-stats | Home-vs-away comparison bars — season aggregates while UPCOMING, that event's match stats once started | Set to "false", or the relevant stats are empty |
| Lineups | data-event-card-show-lineups | Both lineups with headshots, shirt numbers and goal/assist/card/sub badges, collapsible substitutes and coach, or either team's formation on that sport's pitch | Set to "false", or lineups aren't announced |
| Table | data-event-card-show-standings | The competition's standings, involved rows tinted, promotion/qualification/relegation zones marked, columns narrowed on a small card | Set to "false", or the competition has no standings |
| H2H | data-event-card-show-head-to-head | The record over every meeting on record as one bar, over the recent meetings with date, competition crest and both competitors | Set to "false", or no prior meetings |
A show-* attribute can only ever hide a tab — it never forces one on past missing data, which is why there is no empty state: a tab with no data isn't rendered. If none survive, the strip is absent and the card is its header alone.
data-event-card-default-section names the tab to open on. If it isn't in the surviving set it is ignored and the first visible tab opens instead, so "lineups" is safe on a card that may still be upcoming.
<div
data-component="fu-widget"
data-content-type="event-card"
data-content-id="fb:m:12345"
data-event-card-type="detailed"
data-event-card-default-section="h2h"
data-event-card-show-standings="false"
></div>All five sports are handled, not just football. Each changes what the tabs read and how they are labelled: match stats per sport (shots/corners for football, rebounds/turnovers for basketball, faceoffs/power-play goals for hockey, aces/break points for tennis, touchdowns/sacks for American football); sports without draws drop the draw-based streaks and the drawn column; "goals" becomes "points" for basketball, tennis and American football; and the Lineups tab draws that sport's own surface. Sports whose feed lists no bench (basketball, ice hockey, American football) get the squad list only, with no pitch switcher.
All three templates render the same tabs and panel content at the same type scale — only the strip's chrome differs: a horizontally scrolling underline row ("compact"), a segmented pill track ("standard"), or uppercase underline tabs over an inset panel body ("hero").
Betting Odds
Off by default. With data-event-card-show-odds="true", an upcoming or live event shows one market's odds under the scoreboard, in every template, from the first operator in data-event-card-odds-operators that prices the market completely. A finished event shows none. When no operator has a complete market the strip simply does not render, and the operator's own link opens on click either way. The settings are those of the Odds widget, under an odds- prefix — data-event-card-odds-market picks any market listed in Odds Widget → Markets, FT_1X2 by default.
The widget owns no betslip. Set data-event-card-add-to-betslip="true" to push a clicked price into the Betslip widget on the same page as a selection ({matchId}:{market}:{outcome} — e.g. fb:m:123:OVER_GOALS_2_5:OVER). To observe clicks yourself, set eventCard.callbacks.onAddToBetslip in FuWidget.init() — it receives { matchId, market, pick, odd, operatorId } and runs whether or not addToBetslip is on. It takes an argument, so there is no data-attribute equivalent.
<div
data-component="fu-widget"
data-content-type="event-card"
data-content-id="fb:m:12345"
data-event-card-show-odds="true"
data-event-card-odds-market="BOTH_TEAMS_SCORE"
data-event-card-odds-operators="betano-bg,efbet-bg"
data-event-card-add-to-betslip="true"
></div>
<div data-component="fu-widget" data-content-type="betslip"></div>data-event-card-operator-id still works but is deprecated: it stands in for data-event-card-odds-operators with a single operator.
Live Refresh
When data-event-card-live-refresh is true (default) and the event is LIVE, the card re-fetches on data-event-card-refresh-interval so the score/status stay current. Only live events poll — upcoming and finished events are fetched once. Set data-event-card-live-refresh="false" to disable polling.
Predictions
Signed-in users can place Fans United single predictions across several markets, in a collapsible drawer at the bottom of the card.
<div
data-component="fu-widget"
data-content-type="event-card"
data-content-id="fb:m:12345"
data-event-card-predictions-markets="FT_1X2,CORRECT_SCORE_ADVANCED,OVER_GOALS_2_5"
></div>There is no enable flag. The drawer appears only when all of the following hold, and otherwise the card renders exactly as it does without predictions:
- the event is a football event,
- the visitor is signed in (detected automatically),
- at least one supported market is configured,
- the event id resolves to the same fixture in the Football API.
Predictions are made against the Football API, while the card renders Sports API events. The two ids are usually identical but that is not guaranteed, so the widget looks the id up and verifies both team ids and the kickoff time match before offering predictions. If the lookup misses or returns a different fixture, the drawer is not rendered. This costs one extra request, made only for football events with predictions configured for a signed-in user.
Supported Markets
Every market the Prediction API supports (32 in total) can be listed in data-event-card-predictions-markets. Unrecognized values are skipped with a console warning rather than breaking the card.
| Answered by | Markets |
|---|---|
| Home / Draw / Away | FT_1X2, HT_1X2 |
| Two of three outcomes | DOUBLE_CHANCE |
| Half-time / full-time | HT_FT |
| Exact scoreline | CORRECT_SCORE, CORRECT_SCORE_HT, CORRECT_SCORE_ADVANCED |
| A corner count | CORNERS_MATCH |
| Yes / No | BOTH_TEAMS_SCORE, OVER_GOALS_0_5…OVER_GOALS_6_5, OVER_CORNERS_6_5…OVER_CORNERS_13_5, RED_CARD_MATCH, PENALTY_MATCH |
| A player | PLAYER_SCORE, PLAYER_SCORE_FIRST_GOAL, PLAYER_SCORE_TWICE, PLAYER_SCORE_HATTRICK, PLAYER_YELLOW_CARD, PLAYER_RED_CARD |
Player markets pick from both squads (grouped by team, with shirt numbers and headshots) and cost two extra requests, made only when a player market is configured. PLAYER_SCORE_FIRST_GOAL also offers Own goal and No goal will be scored.
Behaviour Over Time
Before the cutoff each market is its own selector row; submitting sends one prediction per market, and only markets the user actually touched are sent. A saved market becomes read-only with edit / remove affordances — each market is its own prediction record, so removing one leaves the others.
After the cutoff, while the match is in play, the drawer is a read-only summary: no editing, but a prediction can still be removed (unless data-event-card-predictions-allow-delete="false"), and removing the last one hides the drawer. Once the match is finished or cancelled the summary is fully read-only and each market shows its outcome and points.
Match Results
Once the event is FINISHED, each market also states what actually happened, on its own line between the question and the user's pick — so a settled market reads: what was asked, what happened, what you said. It needs no configuration: it renders whenever the drawer does on a finished match, with or without showSummary. The drawer heading reports the user's own hit rate ("2/3 right") beside their points total.
Every configured market is listed once graded, including ones the user skipped — before the results are in, a locked drawer lists only what they answered, since naming the rest is noise while nothing can be done about them.
1X2 markets read as the competitor's name or "Draw"; double chance resolves to the single outcome that came in; scorelines as "1 – 1"; yes/no as "Yes"/"No"; player markets name the player, listing several with a "+N" past three.
Prediction Summary
With data-event-card-predictions-show-summary="true", the same drawer also shows how the whole Fans United audience predicted each market. It has no surface of its own — a prediction count in the drawer heading, and each market's split revealed under its row once the user has answered that market. That gate is deliberate: a crowd split beside a live selector anchors the choice to the majority.
| Markets | Drawn as |
|---|---|
| 1X2, double chance, every yes/no market | One stacked bar over a legend naming each outcome and its share |
Scorelines, HT_FT, CORNERS_MATCH, player markets | Ranked rows — the three most popular, with the rest behind an expandable "N more outcomes" toggle |
Bars sit on an absolute 0–100 axis so a percentage means the same length everywhere, and shade by rank — the biggest share at full accent, the rest stepping down. The compact template folds a market's split onto one line as a bar plus the crowd's favourite.
The user's own outcome is called out in the accent colour, and once graded the outcome that actually happened is ticked and coloured green — with the user's own row never faded, even when wrong. Double chance can have two winning outcomes; both are ticked and the combined correct share is reported.
The aggregate is read once with the cache bypassed. The user's own submissions, edits and deletions are folded into the split immediately and locally rather than re-fetched, since a fresh read right after a submit can easily predate the vote.
Presentation
All three templates support predictions; the behaviour is identical and only the presentation differs.
| Template | Drawer |
|---|---|
"compact" | Thin footer strip below the match row — one line per market (question left, control right), crests identifying competitors, horizontal − value + steppers |
"standard" | Full-bleed footer. Each market is a block: question above its control, competitors as crest + name |
"hero" | The same layout as "standard", in a second inset panel below the score panel |
data-event-card-predictions-display="inline" drops the collapse control and renders the markets directly, in every template. Use data-event-card-predictions-default-expanded="true" instead to keep the control but start the drawer open.
Config Object
The global eventCard.predictions object takes the same settings as the attributes above:
| Field | Type | Description |
|---|---|---|
markets | EventCardPredictionMarket[] | Markets to offer, in this order. Omitted or empty means no prediction UI |
display | "drawer" | "inline" | "drawer" (default) collapses the markets behind a footer row; "inline" renders them directly |
cutoffMinutes | number | Minutes before kickoff when predictions close. Defaults to 15, which is also the minimum |
allowDelete | boolean | Let users remove a prediction. Defaults to true |
defaultExpanded | boolean | Start the drawer expanded. Defaults to false. Ignored for "inline" |
showSummary | boolean | Also show the crowd's split per market, inside the same drawer. Defaults to false |
Global Configuration
Set defaults for all Event Card widgets in FuWidget.init():
FuWidget.init({
// ... other config
eventCard: {
template: "standard", // Optional: "compact", "standard" (default), or "hero"
type: "header", // Optional: "header" (default), or "detailed" to add the detail tab strip
showCompetition: true, // Optional: show the competition header (default: true)
// The six flags below and defaultSection apply to type: "detailed" only
showForm: true, // Optional: the Preview tab (default: true)
showTimeline: true, // Optional: the Summary tab (default: true)
showStats: true, // Optional: the Stats tab (default: true)
showLineups: true, // Optional: the Lineups tab (default: true)
showStandings: true, // Optional: the Table tab (default: true)
showHeadToHead: true, // Optional: the H2H tab (default: true)
defaultSection: "stats", // Optional: which tab opens first (default: the first tab of the event's status)
liveRefresh: true, // Optional: poll while the event is LIVE (default: true)
refreshInterval: 30000, // Optional: live-refresh interval in ms (default: 30000)
showOdds: true,
odds: {
market: "FT_1X2", // Default. See Odds Widget → Markets
operators: ["betano-bg", "efbet-bg"], // Preference order — the card shows one operator
affiliateId: "aff-123", // Substituted into operator URLs carrying {affiliate_id}
},
addToBetslip: true,
callbacks: {
onAddToBetslip: (selection) => console.log(selection), // Optional: observe clicked odds prices
},
predictions: {
// Optional: let signed-in users predict football events
markets: ["FT_1X2", "BOTH_TEAMS_SCORE"], // Markets to offer, in this order
display: "drawer", // Optional: "drawer" (default) or "inline"
cutoffMinutes: 15, // Optional: minutes before kickoff when predictions close (default and minimum: 15)
allowDelete: true, // Optional: let users remove a prediction (default: true)
defaultExpanded: false, // Optional: start the drawer expanded (default: false)
showSummary: false, // Optional: also show the crowd's split per market (default: false)
},
},
});A single data-event-card-predictions-* attribute on an element replaces this whole global predictions object for that widget — the two are not merged field by field. Repeat the fields you want to keep as attributes. The odds object is the opposite: data-event-card-odds-* attributes are merged field by field over the global odds.
Examples
Compact Livescore Row
<div data-component="fu-widget" data-content-type="event-card" data-content-id="fb:m:12345" data-event-card-template="compact"></div>Finished Event, No Live Polling
<div data-component="fu-widget" data-content-type="event-card" data-content-id="fb:m:12345" data-event-card-live-refresh="false"></div>Detailed Card, Hero Template
<div
data-component="fu-widget"
data-content-type="event-card"
data-content-id="fb:m:12345"
data-event-card-type="detailed"
data-event-card-template="hero"
></div>Detailed Card Limited To Stats And Head-To-Head
<div
data-component="fu-widget"
data-content-type="event-card"
data-content-id="bb:m:24734"
data-event-card-type="detailed"
data-event-card-show-form="false"
data-event-card-show-timeline="false"
data-event-card-show-lineups="false"
data-event-card-show-standings="false"
data-event-card-default-section="stats"
></div>Compact Card With Inline Predictions
<div
data-component="fu-widget"
data-content-type="event-card"
data-content-id="fb:m:12345"
data-event-card-template="compact"
data-event-card-predictions-markets="FT_1X2,OVER_GOALS_2_5"
data-event-card-predictions-display="inline"
></div>Predictions With The Crowd Summary
<div
data-component="fu-widget"
data-content-type="event-card"
data-content-id="fb:m:12345"
data-event-card-predictions-markets="FT_1X2,CORRECT_SCORE_ADVANCED,BOTH_TEAMS_SCORE"
data-event-card-predictions-show-summary="true"
></div>Predictions Closing an Hour Before Kickoff
<div
data-component="fu-widget"
data-content-type="event-card"
data-content-id="fb:m:12345"
data-event-card-predictions-markets="CORRECT_SCORE_ADVANCED,PLAYER_SCORE_FIRST_GOAL"
data-event-card-predictions-cutoff-minutes="60"
data-event-card-predictions-default-expanded="true"
></div>Features
- Three visual templates —
compact(livescore row),standard(crest beside name flanking the score/time),hero(large stacked crest-over-name in an inset panel with a live accent bar) - Sport-aware status labels — upcoming / live / finished / cancelled, with a clock-vs-tennis finished label (
FTvsFinished) - Tennis per-set scoreboard with tiebreak superscripts, collapsed by default and expandable
- Live auto-refresh while the event is
LIVE, on a configurable interval - Optional betting odds for any supported market under the scoreboard of an upcoming or live event, with a betslip hand-off
- Optional detail tabs (
data-event-card-type="detailed") — Preview, Summary, Stats, Lineups, Table and H2H, chosen by the event's status and by what the provider actually supplies, at no extra request - Per-sport detail content — each sport's own stat keys, streaks, standings columns, wording and lineup pitch
- Optional single predictions for signed-in users — up to 32 markets in a collapsible drawer designed per template (football only)
- Optional crowd summary — how the whole audience predicted each market, revealed inside the same drawer
- Graded match results per market once the event finishes, alongside the user's own outcome and points
- Contained load-failed / not-available states that never break the host layout
Updated 3 days ago
