Skip to content
txbrendan/ui

Line Score

beta

A baseball line score: each team's runs by inning on number plates, then lit runs, hits, and errors, with the half-inning in play marked.

Preview

A run scores in the half-inning in play, and the total rolls

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

A finished game, with "X" for the half the home side did not bat

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

Extra innings add columns, and the innings scroll in a narrow space

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

On a dark green board, with --line-score-surface set to match

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

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/line-score

Use it for

  • The top of a baseball scoreboard, a game page, or a game card that needs every inning.
  • Pass each team's runs by inning. Leave an inning out until it starts, and its plate stays empty.
  • Pass "X" for a half that was never played, like the home side's last when it already leads.
  • Pass inning while the game is on, like { number: 5, half: "top" }. Its plate is outlined and the caption says "Top of the 5th".
  • Leave inning out once the game is over, and pass status, like "Final".
  • Runs total themselves. Hits and errors come from your data.
  • On a surface other than a card, set --line-score-surface to its color, so the team names cover the innings as they scroll.

Avoid it for

  • A game with no innings, like football or rugby. Use MatchCard.
  • Only the final score. Print it, or use MatchCard.
  • More than two teams. A line score is one game.

Props

  • away

    The visitors, who bat first: { name, short?, runs, hits?, errors? }. runs is (number | "X")[], by inning.

    LineScoreTeam

  • home

    The home side, who bat in the bottom of each inning. The same shape as away.

    LineScoreTeam

  • innings

    How many innings the game is scheduled for. Extra innings add columns.

    number · default 9

  • inning

    The half-inning being played now. Leave it out before the game and once it is over.

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

  • status

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

    string

  • caption

    The table's name.

    string · default "Line score"

  • className

    Extra classes on the outer div, which holds the container query. Later classes win.

    string

Accessibility

  • It is a table with a caption. Each team is a row header, and each inning, R, H, and E is a column header.
  • Screen readers hear "Inning 5", not just "5", and Runs, Hits, and Errors in full.
  • On a narrow board the short name shows, and screen readers still hear the full one.
  • The half in play is outlined, and the caption says it in words, like "Top of the 5th". The outline still shows in forced colors.
  • An inning that has not started reads "no score".
  • One polite line says each scoring change once, like "Rivers score 2 runs in the 4th. Harbor 1, Rivers 5." Never on load, and never for a pitch.
  • The innings take a Tab stop only when they scroll sideways, so a keyboard can scroll them too. Then they are a region named by the caption.
  • Runs, hits, and errors roll to each new value. Reduced motion and motion off jump straight there.

Examples

A game in the bottom of the 4th

<LineScore
  away={{ name: "Harbor", short: "HAR", runs: [0, 1, 0, 0], hits: 4, errors: 1 }}
  home={{ name: "Rivers", short: "RIV", runs: [1, 0, 2], hits: 3 }}
  inning={{ number: 4, half: "bottom" }}
/>

A finished game where the home side did not bat in the 9th

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

On a dark board of your own

<div className="dark bg-success-soft p-4 text-foreground [--line-score-surface:var(--success-soft)]">
  <LineScore away={away} home={home} inning={inning} />
</div>