Skip to content
txbrendan/ui

Suspension Row

beta

A player in the sin bin, sent off, or off for a temporary replacement, as a row in a card, counting down on the same clock value as MatchClock.

Preview

Players off
Second half50:00
#3Owen PriceBack in 4:00Rovers · Yellow card at 46:30
#12Dan KerrBack in 0:15Saints · Yellow card at 40:15
#6Ben WardSent offSaints · Red card at 31:02
#8Sam LeeReplacement in 7:30Rovers · 20-minute red card at 38:10
#1Will HardyBack within 15:00Saints · Blood replacement
#10Tom HaleBack within 17:00Rovers · Head injury assessment

Full time at 80 min

#3Owen PriceCan returnRovers · Yellow card at 40:00Owen Price: Can return
#1Will HardyBack within 15:00Saints · Blood replacement
#4Ava PatelBack in 2:00Lions · Yellow card at 2:40

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/suspension-row

Use it for

  • One row per player off, in a Card, beside the MatchClock on a scorer's or timekeeper's screen.
  • Pass the match's clock value and format, the same ones the MatchClock gets. A card counts down on playing time: it stops when the clock stops, carries over half-time, and counts the time played after time is up.
  • Record at as matchPlayed(clock) and time as matchClockDisplay(clock, format) when the card is shown.
  • yellow uses the format's sin bin: 10 minutes in 15s, 2 in sevens and 10s, 5 to 7 in the age grades. Pass minutes when a competition sets its own.
  • red reads Sent off for the rest of the match. red20 is elite rugby's 20-minute red card: after 20 minutes of playing time a replacement may come on.
  • blood and hia are temporary replacements on the wall clock, from since: 15 minutes for blood, 12 for an HIA, or minutes={17} for both.
  • Pass onReturn. A person button beside Can return, or Back within, brings them back on.
  • Remove the row once the player is back on. A team's players on the field is its format's players less its rows.

Avoid it for

  • A row for a suspected concussion in community or age-grade rugby. Recognise and Remove takes them off for good, which is a permanent replacement, not a row.
  • Your own countdown timer. The row works out the time from the clock value, so every device agrees.
  • Telling the cards apart by the mark's color alone. The words under the name say which card it is.

Props

  • player

    The player, with their photo and shirt number.

    { person: string; photo?: string; number?: number }

  • team

    The player's team, in the line under the name.

    string

  • reason

    Why the player is off: a card, or a temporary replacement.

    "yellow" | "red" | "red20" | "blood" | "hia"

  • clock

    The match's MatchClock value.

    MatchClockValue | null

  • format

    The same format as the MatchClock. It sets the sin bin.

    MatchFormatId | MatchFormat · default "15s"

  • at

    matchPlayed(clock) when the card was shown. Cards only.

    number · default 0

  • time

    What the clock read when it was shown, like "8:25".

    string

  • minutes

    Minutes off, when a competition sets its own sin bin, or 17 for blood and an HIA together.

    number

  • since

    blood and hia: when the player left, in ms since the epoch.

    number

  • onReturn

    Brings them back on, or a replacement on. A person button shows once it can.

    () => void

  • index

    Place in a list. Rows fade up one after another as they first show.

    number

  • divider

    A hairline above the row, inset from the card's edges.

    boolean · default false

  • className

    Extra classes. Later classes win.

    string

Accessibility

  • The row reads as one line: the number, the name, and the status, like "#3 Owen Price · Back in 4:12".
  • Which card it is, or why they are off, is in words in the line under the name. The card mark before those words is hidden from screen readers.
  • The return button is a native button named for what it does, like "Bring Owen Price back on", with the same words in its tooltip.
  • A polite live region says once when the time is served, like "Owen Price: Can return". The countdown itself is not read out each second.
  • Can return, Sent off, and Replacement stays are words in the tone's soft text, which the theme holds to 4.5:1. A card mark keeps a border in forced-colors mode.

Examples

A yellow card counting down beside the clock

// clock is the match's MatchClock value. at and time were recorded when the card was shown.
<Card className="gap-0 px-0">
  <SuspensionRow
    player={{ person: "Owen Price", number: 3 }}
    team="Rovers"
    reason="yellow"
    at={card.at}
    time={card.time}
    clock={clock}
    format="15s"
    onReturn={() => bringBack("owen")}
  />
</Card>

A blood replacement on the wall clock

<SuspensionRow
  player={{ person: "Will Hardy", number: 1 }}
  team="Saints"
  reason="blood"
  since={leftAt}
  clock={clock}
  onReturn={() => bringBack("will")}
  divider
/>