Fixtures

Animated tournament fixtures in two styles: a knockout bracket that pages through rounds, and a wheel that wraps the same tree around the champion. Both read the same array of rounds, so one dataset draws either.

Knockout Wheel

knockout-wheel.tsx

The tournament drawn radially. The champion holds the hub, each round is a ring further out, and the teams themselves form the rim. Nodes spring in ring by ring, and hovering one isolates that team while the rest recede. Teams show a flag, a logo or their initials, and a deeper draw grows another ring.

SSASBSPSJSCRJSNPNEGPEBEUEWCUCBCDBCFAFIFMFPSMBIBTSIAGAMAPQMGNGSAN
  • Spain v Argentina · 2–1
  • Spain v Brazil · 2–1
  • France v Argentina · 0–0 (3–4 pens)
  • Spain v Portugal · 1–0
  • England v Brazil · 2–3
  • France v Italy · 2–1
  • Argentina v Germany · 3–1
  • Spain v Japan · 2–0
  • Netherlands v Portugal · 1–3
  • England v Uruguay · 2–1
  • Croatia v Brazil · 0–1
  • France v Morocco · 3–1
  • Belgium v Italy · 1–2
  • Argentina v Mexico · 2–0
  • Germany v Norway · 1–1 (4–2 pens)
  • Spain v Costa Rica · 3–0
  • Japan v Serbia · 2–1
  • Netherlands v Ecuador · 2–0
  • Ghana v Portugal · 2–3
  • England v Wales · 4–0
  • Canada v Uruguay · 0–2
  • Croatia v Denmark · 1–0
  • Brazil v Cameroon · 3–1
  • France v Poland · 2–1
  • Senegal v Morocco · 0–1
  • Belgium v Tunisia · 2–0
  • Switzerland v Italy · 1–3
  • Argentina v Peru · 2–0
  • Qatar v Mexico · 0–1
  • Germany v Sweden · 4–2
  • Austria v Norway · 1–2

Install

$ bunx --bun shadcn add @beui/knockout-wheel

API Reference

rounds
{}

The whole draw, ordered widest round first — the same array the knockout bracket takes. Any single-elimination tournament fits: each round holds half the matches of the one before it (16 → 8 → 4 → 2 → 1) and `rounds[r].matches[k]` is fed by matches `2k` and `2k + 1` of the round before it. Two rounds are enough; the wheel grows a ring per round and sizes itself to the rim.

initialRound?
number

Index of the outermost round to draw. Earlier rounds are dropped and the kept round's own teams become the rim, so `1` on a 32-team draw opens at the Round of 16. Defaults to 0 (the whole tree); clamped to the valid range.

0
className?
string

Knockout Bracket

knockout-bracket.tsx

Pages one round at a time. The leftmost round stacks at a fixed rhythm, each later round centers between its two feeder matches, and cards, elbow connectors, headers and stage height animate into every new layout. A third place play-off sits below the tree under its own rule. Round names, team artwork, dates and result chips all come from the data you pass.

Showing Round of 16, Quarter-finals, and Semi-finals
Round of 16
Quarter-finals
Semi-finals
  • Sat, 4 JulFT
    Canada0
    Morocco3
  • Sun, 5 JulFT
    Paraguay0
    France1
  • Mon, 6 JulFT
    USA1
    Belgium4
  • Mon, 6 JulFT
    Portugal0
    Spain1
  • Mon, 6 JulFT
    Brazil1
    Norway2
  • Mon, 6 JulFT
    Mexico2
    England3
  • Tue, 7 JulFT (P)
    Switzerland0 (4)
    Colombia0 (3)
  • Tue, 7 JulFT
    Argentina3
    Egypt2
  • Fri, 10 Jul, 4:00 amFT
    France2
    Morocco0
  • Sat, 11 Jul, 3:00 amFT
    Spain2
    Belgium1
  • TodayFT
    Norway1
    England2
  • TodayFT
    Argentina3
    Switzerland1
  • Wed, 15 Jul, 4:00 am
    France
    Spain
  • Thu, 16 Jul, 3:00 am
    England
    Argentina
  • Third place play-off

    Sun, 19 Jul, 3:00 am
    TBD
    TBD

Install

$ bunx --bun shadcn add @beui/knockout-bracket

API Reference

rounds
{}

The whole draw, ordered widest round first. Any single-elimination tournament fits: each round holds half the matches of the one before it (16 → 8 → 4 → 2 → 1) and `rounds[r].matches[k]` is fed by matches `2k` and `2k + 1` of the round before it. Two rounds are enough.

initialRound?
number

Round shown as the leftmost column on mount. Defaults to 1, clamped to the valid range.

1
thirdPlace?
Match

Third place play-off, rendered under the bracket instead of inside it.

thirdPlaceLabel?
string

Heading over `thirdPlace`. Defaults to "Third place play-off".

Third place play-off
className?
string

Keep in mind

Some components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.

Updated