Skip to content
txbrendan/ui

Leaderboard

beta

Ranked people for one number, on DataTable: the place, the person, and the value. Ties share a place, and your row follows a Your place line.

Preview

unit, you outside the top 5, ties, no value

Tickets closed
#NameTickets
1Mia OkaforSupport9
=2Cal NashSales7
=2Tom HaleSupport7
4Ana RuizDesign4
=5Sam CarterEngineering3
Your place
7You, Josh TaitSupport2

better lower, format, you in the top

Time to first reply
#NameTime
1Cal Nash4:51
2Mia Okafor4:57
3You, Josh Tait5:05
4Ana Ruiz5:18
5Tom Hale5:42

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/leaderboard

Use it for

  • One number per person: tickets closed, sales, minutes, a test score. Put it in a Card with className="px-0", and name it with the card's title through aria-labelledby.
  • Equal values share a place, like "=3", and the next place skips them. People with no value are left out.
  • you marks your row with a blue bar and its own wash. Outside the top limit, your row follows a Your place line.
  • better="lower" ranks times and the like. format draws the value, like seconds as 12:34.

Avoid it for

  • Many numbers per person, or a sort the reader picks. Use DataTable.
  • Teams in a league. Use Standings.

Props

  • items

    Required. The people, in any order. meta shows under the name, like a team or a position.

    { id: string; person: string; photo?: string; meta?: string; value: number | null }[]

  • unit

    Names the value column, like "tickets". Its first letter is made a capital.

    string · default "score"

  • better

    Which way ranks first.

    "higher" | "lower" · default "higher"

  • you

    Your item's id.

    string

  • limit

    How many rows show before your own place.

    number · default 5

  • format

    Draws a value. Ties still compare the numbers.

    (value: number) => string

  • label

    The people column's header.

    string · default "Player"

  • caption

    Names the table, under it.

    ReactNode

  • aria-label

    Names the table when it has no caption.

    string

  • aria-labelledby

    Names the table by another element, like the Card's title.

    string

  • loading

    Holds the space with placeholder rows.

    boolean · default false

  • empty

    What shows when no one has a value.

    ReactNode · default "No scores yet"

  • className

    Extra classes on the wrapper. Later classes win.

    string

Accessibility

  • A real <table>. Each person's name is the row header, so the place and the value are read with it.
  • Your row starts with "You," for screen readers. Its bar is a border, so it stays in forced colors.
  • The Your place line is a row of its own, with words, so it is read in order.

Examples

Your row after the top 5, with a tie

<Leaderboard
  aria-label="Tickets closed"
  unit="tickets"
  label="Name"
  you="p6"
  items={[
    { id: "p1", person: "Mia Okafor", meta: "Support", value: 9 },
    { id: "p2", person: "Cal Nash", meta: "Sales", value: 7 },
    { id: "p3", person: "Tom Hale", meta: "Support", value: 7 },
    { id: "p4", person: "Ana Ruiz", meta: "Design", value: 4 },
    { id: "p5", person: "Sam Carter", meta: "Engineering", value: 3 },
    { id: "p6", person: "Josh Tait", meta: "Support", value: 2 },
  ]}
/>