Skip to content
txbrendan/ui

Scoreboard

beta

A ballpark scoreboard on a dark green board: the line score across the top, then the count, both batting orders, the umpires, and other games around the league.

Built from Line Score, Ball Count, Batting Order, League Scores, and Skeleton.

Preview

Line score · Bottom of the 4th
Inning 1Inning 2Inning 3Inning 4Inning 5Inning 6Inning 7Inning 8Inning 9RHE
Harbor0100no scoreno scoreno scoreno scoreno score141
Rivers1020no scoreno scoreno scoreno scoreno score330

Balls
1
Strikes
2
Outs
1
At bat
24
Avg
.267

Umpires

Plate
17
1B
21
2B
14
3B
2
Harbor batting order
No.Pos.
11Shortstop
18Second base
26Left field
10Third base
14First base
9Catcher
25Right field
20Center field
48Pitcher
Rivers batting order
No.Pos.
17Right field
15Second base
14Left field
28Center field
24Third base, at bat
19Shortstop
11First base
7Catcher
35Pitcher
North
InningTeamRunsPitcher
9Bay510
Pine610
7Oak24
Lake010
9Ash75
Elm58
7Mill09
Ford09
Bay here Mon, Tue & Wed
South
InningTeamRunsPitcher
5Cove01
Dale13
FRidge81
Vale44
4Moor23
Glen110
5Fern76
Holt52

Made from these parts, each on its own: Line Score, Ball Count, Batting Order, and League Scores

Line score · Bottom of the 4th
Inning 1Inning 2Inning 3Inning 4Inning 5Inning 6Inning 7Inning 8Inning 9RHE
Harbor0100no scoreno scoreno scoreno scoreno score141
Rivers102no scoreno scoreno scoreno scoreno scoreno score330

Balls
1
Strikes
2
Outs
1
At bat
24
Avg
.267
Rivers batting order
No.Pos.
17Right field
15Second base
14Left field
28Center field
24Third base, at bat
North
InningTeamRunsPitcher
9Bay510
Pine610
7Oak24
Lake010

A finished game with no inning in play

Line score · Final
Inning 1Inning 2Inning 3Inning 4Inning 5Inning 6Inning 7Inning 8Inning 9RHE
Harbor010020010491
Rivers10210010X580

Extra innings add columns

Line score · Bottom of the 11th
Inning 1Inning 2Inning 3Inning 4Inning 5Inning 6Inning 7Inning 8Inning 9Inning 10Inning 11RHE
Harbor010020010015111
Rivers1021000000no score4102

Balls
3
Strikes
2
Outs
2

Loading

Loading the scoreboard

No game on the board

No game today. Next home game Friday.

In a narrow column

Line score · Bottom of the 4th
Inning 1Inning 2Inning 3Inning 4Inning 5Inning 6Inning 7Inning 8Inning 9RHE
Harbor0100no scoreno scoreno scoreno scoreno score141
Rivers1020no scoreno scoreno scoreno scoreno score330

Balls
1
Strikes
2
Outs
1
At bat
24
Harbor batting order
No.Pos.
11Shortstop
18Second base
26Left field
10Third base
14First base
9Catcher
25Right field
20Center field
48Pitcher
Rivers batting order
No.Pos.
17Right field
15Second base
14Left field
28Center field
24Third base, at bat
19Shortstop
11First base
7Catcher
35Pitcher

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 block. It also adds every component it uses. Its own files go in your components folder, and they are yours to edit.

    npx shadcn@latest add @txbrendan/scoreboard

Use it for

  • A live baseball game page, a stadium screen, or a fan site's game center.
  • Pass away and home with their runs by inning, hits, errors, and lineup. Then the rest as you have it: count, batter, umpires, and leagues.
  • Pass inning while the game is on. Its team's lineup marks the batter, by batter.number.
  • Leave inning and count out once the game is over, and pass status, like "Final".
  • Each panel shows only when it has data, so a board with just a line score works too.
  • The board stays dark green in light mode and dark. It scopes the theme's dark tokens to itself with the dark class.

Avoid it for

  • A board that follows the page's light and dark mode. Use LineScore and the other parts on your own card.
  • Games with no innings. Use MatchCard.

Props

  • away

    The visitors: a LineScoreTeam plus lineup?, their batting order. With home, the game on the board.

    ScoreboardTeam

  • home

    The home side, the same shape.

    ScoreboardTeam

  • innings

    How many innings the game is scheduled for.

    number · default 9

  • inning

    The half-inning being played now.

    { number: number; half: "top" | "bottom" }

  • status

    A word for the game's state when no inning is in play, like "Final".

    string

  • count

    The count now. Leave it out to hide the count.

    { balls: number; strikes: number; outs: number }

  • batter

    Who is at the plate.

    { number: number; average?: string }

  • leagues

    Other games, one table per group.

    { title: string; games: LeagueScoresGame[]; note?: ReactNode }[] · default []

  • umpires

    The umpires by base, like { label: "Plate", number: 17 }.

    { label: string; number: number }[] · default []

  • loading

    Shows placeholder tiles while the game loads.

    boolean · default false

  • loadingText

    What the status line tells screen readers while loading.

    string · default "Loading the scoreboard"

  • emptyText

    Shown when there is no game and nothing is loading.

    string · default "No game on the board."

  • className

    Extra classes on the board, which holds the container query.

    string

Accessibility

  • The board is a section named "Scoreboard". Pass aria-label to name it after the game.
  • Each part keeps its own table or list, so screen readers can move by table and by row.
  • The line score says each scoring change once in a polite line. The count does not, since it changes every pitch.
  • On the dark green board, white text is 12.6:1, the lit amber is 9.6:1, and the muted labels are 5.5:1.
  • While loading, the board has aria-busy="true" and a status line says loadingText.

Examples

A game in progress

<Scoreboard
  away={{ name: "Harbor", short: "HAR", runs: [0, 1, 0, 0], hits: 4, errors: 1, lineup: harborLineup }}
  home={{ name: "Rivers", short: "RIV", runs: [1, 0, 2], hits: 3, lineup: riversLineup }}
  inning={{ number: 4, half: "bottom" }}
  count={{ balls: 1, strikes: 2, outs: 1 }}
  batter={{ number: 24, average: ".267" }}
/>

A final score with nothing else

<Scoreboard away={{ name: "Harbor", runs: [0, 1, 0, 0, 2, 0, 0, 1, 0], hits: 9 }} home={{ name: "Rivers", runs: [1, 0, 2, 1, 0, 0, 1, 0, "X"], hits: 8 }} status="Final" />

While the game loads

<Scoreboard loading />