Skip to content
txbrendan/ui

Match Card

beta

A knockout match tile with a flat shape: the time and pitch, an FT or Live badge, and two team rows with kit, score, and the winner's caret.

Preview

before kick-off: no status, no badge

15:20 · Pitch 2QF 3 winnerQF 4 winner
16:00 · Pitch 1RoversLions

status: Live, then FT with the winner's caret

15:00 · Pitch 1Live 9'Rovers7Lions0
15:00 · Pitch 1FTRovers24Lions17 Rovers won.

a level score with penalties reads FT (P), and the side with more kicks goes through

16:00 · Pitch 2FT (P)Hawks(3)14Wolves(4)14 Wolves won 4–3 on kicks.
16:00 · Pitch 2AETHawks20Wolves17 Hawks won.

width={280}, and never under 240

13:00 · Pitch 3FTLions12Hawks19 Hawks won.
14:00 · Pitch 3WolvesRovers

Install

  1. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. Add the component.

    npx shadcn@latest add @txbrendan/match-card

Use it for

  • A knockout match from data shaped as two teams, each with its own score, like a match day list.
  • Pass when as the time and pitch, like "15:20 · Pitch 2".
  • Pass status "FT" once it's finished, "Live 9'" while it's on, or leave it out before kick-off.
  • At FT the side with the higher score gets the caret. On a level score, pass each side's penalties, and the one with more goes through.
  • Pass onClick and selected to make it a match you choose.

Avoid it for

  • A draw of many rounds. Use KnockoutBracket.
  • A match that needs a peek with the round's name. Use BracketMatch.
  • A league match that can end level. A level FT with no kicks shows no winner, which reads oddly in a cup but is right in a league, so say the result elsewhere.

Props

  • when

    The time and pitch, like "15:20 · Pitch 2".

    string

  • status

    "FT", "Live 9'", or another word like "AET". Left out before kick-off. Any word but Live means it's over.

    string

  • home

    { name, score?, penalties?, colors?, pattern? }. colors are the kit's two colors, as KitColors.

    MatchTeam

  • away

    The same shape as home.

    MatchTeam

  • selected

    Draws it as the chosen match. Only a card with onClick can be chosen.

    boolean · default false

  • onClick

    Makes the card a button that says whether it is pressed.

    () => void

  • width

    A fixed width in px, never under 240. By default it fills its column.

    number

  • className

    Extra classes. Later classes win.

    string

Accessibility

  • The card names both teams and their scores, and says who won in text. The caret and the weight only show it.
  • After kicks, it reads FT (P), shows each side's kicks in brackets, and says "won 4–3 on kicks".
  • With onClick, it is a button with aria-pressed. A chosen card has a 2px outline that shows in forced colors.
  • A Live badge says Live in words. Its red is not the only sign.

Examples

Before kick-off

<MatchCard when="15:20 · Pitch 2" home={{ name: "QF 3 winner" }} away={{ name: "QF 4 winner" }} />

Finished, after kicks

<MatchCard
  when="16:00 · Pitch 1"
  status="FT"
  home={{ name: "Hawks", score: 14, penalties: 3 }}
  away={{ name: "Wolves", score: 14, penalties: 4 }}
/>

Live, and chosen

<MatchCard
  when="15:00 · Pitch 1"
  status="Live 9'"
  home={{ name: "Rovers", score: 7, colors: kit, pattern: "hoops" }}
  away={{ name: "Lions", score: 0 }}
  selected={selected === "final"}
  onClick={() => setSelected("final")}
/>