Scoreboard
betaA 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
| Inning 1 | Inning 2 | Inning 3 | Inning 4 | Inning 5 | Inning 6 | Inning 7 | Inning 8 | Inning 9 | R | H | E | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Harbor | 0 | 1 | 0 | 0 | no score | no score | no score | no score | no score | 1 | 4 | 1 |
| Rivers | 1 | 0 | 2 | 0 | no score | no score | no score | no score | no score | 3 | 3 | 0 |
- Balls
- 1
- Strikes
- 2
- Outs
- 1
- At bat
- 24
- Avg
- .267
Umpires
- Plate
- 17
- 1B
- 21
- 2B
- 14
- 3B
- 2
| No. | Pos. |
|---|---|
| 11 | Shortstop |
| 18 | Second base |
| 26 | Left field |
| 10 | Third base |
| 14 | First base |
| 9 | Catcher |
| 25 | Right field |
| 20 | Center field |
| 48 | Pitcher |
| No. | Pos. |
|---|---|
| 17 | Right field |
| 15 | Second base |
| 14 | Left field |
| 28 | Center field |
| 24 | Third base, at bat |
| 19 | Shortstop |
| 11 | First base |
| 7 | Catcher |
| 35 | Pitcher |
| Inning | Team | Runs | Pitcher |
|---|---|---|---|
| 9 | Bay | 5 | 10 |
| Pine | 6 | 10 | |
| 7 | Oak | 2 | 4 |
| Lake | 0 | 10 | |
| 9 | Ash | 7 | 5 |
| Elm | 5 | 8 | |
| 7 | Mill | 0 | 9 |
| Ford | 0 | 9 | |
| Bay here Mon, Tue & Wed | |||
| Inning | Team | Runs | Pitcher |
|---|---|---|---|
| 5 | Cove | 0 | 1 |
| Dale | 1 | 3 | |
| F | Ridge | 8 | 1 |
| Vale | 4 | 4 | |
| 4 | Moor | 2 | 3 |
| Glen | 1 | 10 | |
| 5 | Fern | 7 | 6 |
| Holt | 5 | 2 |
Made from these parts, each on its own: Line Score, Ball Count, Batting Order, and League Scores
| Inning 1 | Inning 2 | Inning 3 | Inning 4 | Inning 5 | Inning 6 | Inning 7 | Inning 8 | Inning 9 | R | H | E | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Harbor | 0 | 1 | 0 | 0 | no score | no score | no score | no score | no score | 1 | 4 | 1 |
| Rivers | 1 | 0 | 2 | no score | no score | no score | no score | no score | no score | 3 | 3 | 0 |
- Balls
- 1
- Strikes
- 2
- Outs
- 1
- At bat
- 24
- Avg
- .267
| No. | Pos. |
|---|---|
| 17 | Right field |
| 15 | Second base |
| 14 | Left field |
| 28 | Center field |
| 24 | Third base, at bat |
| Inning | Team | Runs | Pitcher |
|---|---|---|---|
| 9 | Bay | 5 | 10 |
| Pine | 6 | 10 | |
| 7 | Oak | 2 | 4 |
| Lake | 0 | 10 |
A finished game with no inning in play
| Inning 1 | Inning 2 | Inning 3 | Inning 4 | Inning 5 | Inning 6 | Inning 7 | Inning 8 | Inning 9 | R | H | E | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Harbor | 0 | 1 | 0 | 0 | 2 | 0 | 0 | 1 | 0 | 4 | 9 | 1 |
| Rivers | 1 | 0 | 2 | 1 | 0 | 0 | 1 | 0 | X | 5 | 8 | 0 |
Extra innings add columns
| Inning 1 | Inning 2 | Inning 3 | Inning 4 | Inning 5 | Inning 6 | Inning 7 | Inning 8 | Inning 9 | Inning 10 | Inning 11 | R | H | E | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Harbor | 0 | 1 | 0 | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 1 | 5 | 11 | 1 |
| Rivers | 1 | 0 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | no score | 4 | 10 | 2 |
- 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
| Inning 1 | Inning 2 | Inning 3 | Inning 4 | Inning 5 | Inning 6 | Inning 7 | Inning 8 | Inning 9 | R | H | E | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Harbor | 0 | 1 | 0 | 0 | no score | no score | no score | no score | no score | 1 | 4 | 1 |
| Rivers | 1 | 0 | 2 | 0 | no score | no score | no score | no score | no score | 3 | 3 | 0 |
- Balls
- 1
- Strikes
- 2
- Outs
- 1
- At bat
- 24
| No. | Pos. |
|---|---|
| 11 | Shortstop |
| 18 | Second base |
| 26 | Left field |
| 10 | Third base |
| 14 | First base |
| 9 | Catcher |
| 25 | Right field |
| 20 | Center field |
| 48 | Pitcher |
| No. | Pos. |
|---|---|
| 17 | Right field |
| 15 | Second base |
| 14 | Left field |
| 28 | Center field |
| 24 | Third base, at bat |
| 19 | Shortstop |
| 11 | First base |
| 7 | Catcher |
| 35 | Pitcher |
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the block. It also adds every component it uses. Its own files go in your
componentsfolder, 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
| Prop | Type | Default | What it does |
|---|---|---|---|
| away | ScoreboardTeam | - | The visitors: a LineScoreTeam plus lineup?, their batting order. With home, the game on the board. |
| home | ScoreboardTeam | - | The home side, the same shape. |
| innings | number | 9 | How many innings the game is scheduled for. |
| inning | { number: number; half: "top" | "bottom" } | - | The half-inning being played now. |
| status | string | - | A word for the game's state when no inning is in play, like "Final". |
| count | { balls: number; strikes: number; outs: number } | - | The count now. Leave it out to hide the count. |
| batter | { number: number; average?: string } | - | Who is at the plate. |
| leagues | { title: string; games: LeagueScoresGame[]; note?: ReactNode }[] | [] | Other games, one table per group. |
| umpires | { label: string; number: number }[] | [] | The umpires by base, like { label: "Plate", number: 17 }. |
| loading | boolean | false | Shows placeholder tiles while the game loads. |
| loadingText | string | "Loading the scoreboard" | What the status line tells screen readers while loading. |
| emptyText | string | "No game on the board." | Shown when there is no game and nothing is loading. |
| className | string | - | Extra classes on the board, which holds the container query. |
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 />