Leaderboard
betaRanked 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
| # | Name | Tickets |
|---|---|---|
| 1 | Mia Okafor | 9 |
| =2 | Cal Nash | 7 |
| =2 | Tom Hale | 7 |
| 4 | Ana Ruiz | 4 |
| =5 | Sam Carter | 3 |
| Your place | ||
| 7 | You, Josh Tait | 2 |
better lower, format, you in the top
| # | Name | Time |
|---|---|---|
| 1 | Cal Nash | 4:51 |
| 2 | Mia Okafor | 4:57 |
| 3 | You, Josh Tait | 5:05 |
| 4 | Ana Ruiz | 5:18 |
| 5 | Tom Hale | 5:42 |
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 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
| Prop | Type | Default | What it does |
|---|---|---|---|
| items | { id: string; person: string; photo?: string; meta?: string; value: number | null }[] | - | Required. The people, in any order. meta shows under the name, like a team or a position. |
| unit | string | "score" | Names the value column, like "tickets". Its first letter is made a capital. |
| better | "higher" | "lower" | "higher" | Which way ranks first. |
| you | string | - | Your item's id. |
| limit | number | 5 | How many rows show before your own place. |
| format | (value: number) => string | - | Draws a value. Ties still compare the numbers. |
| label | string | "Player" | The people column's header. |
| caption | ReactNode | - | Names the table, under it. |
| aria-label | string | - | Names the table when it has no caption. |
| aria-labelledby | string | - | Names the table by another element, like the Card's title. |
| loading | boolean | false | Holds the space with placeholder rows. |
| empty | ReactNode | "No scores yet" | What shows when no one has a value. |
| className | string | - | Extra classes on the wrapper. Later classes win. |
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 },
]}
/>