Fixtures Knockout Bracket
beui/knockout-bracketFreeBlock
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.
Install it
npx shadcn@latest add https://beui.dev/r/knockout-bracket.jsonSource
1"use client";2// beui.dev/components/blocks/knockout-bracket34import { ChevronLeft, ChevronRight, Shield } from "lucide-react";5import { motion, useReducedMotion } from "motion/react";6import { useMemo, useState } from "react";7import { EASE_OUT } from "@/lib/ease";8import { cn } from "@/lib/utils";910export type Team = {11 name: string;12 /**13 * Any square image URL — club crest, org mark, player photo. Wins over `code`.14 * Drawn as-is on the card surface, so a transparent-background mark inked for15 * one theme disappears in the other: ship artwork that reads on both, or pick16 * the URL yourself from your theme state.17 */18 logo?: string;19 /** ISO 3166-1 alpha-2 code, loaded from flagcdn.com (England is gb-eng). Used when `logo` is absent. */20 code?: string;21};2223export type MatchSide = {24 /** null renders a TBD slot with a shield icon. */25 team: Team | null;26 score: number | null;27 /** Present on both sides to render Google-style shootout scores — 1 (3). */28 penalties?: number | null;29};3031export type Match = {32 id: string;33 /** Kick-off day, already formatted. Omit it and the card drops the date row. */34 date?: string;35 time?: string;36 /** Omit it and a match with a `winner` counts as finished. */37 status?: "finished" | "upcoming";38 home: MatchSide;39 away: MatchSide;40 /** Decides the marker and which side dims. */41 winner?: "home" | "away";42 /** Replaces the derived result chip ("FT", "FT (P)") — e.g. "AET", "BO5", "Forfeit". */43 badge?: string;44};4546export type Round = {47 /** Shown as the column header — "Round of 32", "Upper bracket final", "Last 8". */48 name: string;49 matches: Match[];50};5152export interface KnockoutBracketProps {53 /**54 * The whole draw, ordered widest round first. Any single-elimination55 * tournament fits: each round holds half the matches of the one before it56 * (16 → 8 → 4 → 2 → 1) and `rounds[r].matches[k]` is fed by matches `2k` and57 * `2k + 1` of the round before it. Two rounds are enough.58 */59 rounds: Round[];60 /** Round shown as the leftmost column on mount. Defaults to 1, clamped to the valid range. */61 initialRound?: number;62 /** Third place play-off, rendered under the bracket instead of inside it. */63 thirdPlace?: Match;64 /** Heading over `thirdPlace`. Defaults to "Third place play-off". */65 thirdPlaceLabel?: string;66 className?: string;67}686970// Card geometry drives the whole computed layout — every later match sits at the71// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| File Upload Attachment Uploadattachment-upload | beui | Blocks | Free | 4 deps · 5 files | |
| Availability Scheduleravailability-scheduler | beui | Blocks | Free | 4 deps · 15 files | |
| Bloom Menubloom-menu | beui | Blocks | Free | 4 deps · 3 files | |
| Command Palettecommand-palette | beui | Blocks | Free | 4 deps · 3 files | |
| Dynamic Islanddynamic-island | beui | Blocks | Free | 3 deps · 3 files | |
| Expandable Action Barexpandable-action-bar | beui | Blocks | Free | 3 deps · 2 files | |
| Expandable Tabsexpandable-tabs | beui | Blocks | Free | 3 deps · 3 files | |
| Feedback Widgetfeedback-widget | beui | Blocks | Free | 4 deps · 9 files |
