Leaderboard Rankings
trophy/leaderboard-rankingsFreeComponent
React leaderboard rankings list—avatars, scores, bylines, and crown highlights for full tables. Open-source leaderboard UI for games, communities, and SaaS challenges. shadcn/ui + Tailwind.
Live preview
live · rendered by the registry
Rendered by trophy on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.trophy.so/r/leaderboard-rankings.jsonSource
1"use client"23import * as React from "react"4import {5 ChevronLeft,6 ChevronRight,7 CircleEllipsisIcon,8 Crown,9 EllipsisIcon,10 TrendingDown,11 TrendingUp,12} from "lucide-react"1314import { cn } from "@/lib/utils"15import { Button } from "@/components/ui/button"1617interface LeaderboardRankingItem {18 userId: string19 userName: string | null20 rank: number21 value: number22 byline?: string | null23 avatarUrl?: string | null24 rankChange?: number25 displayed?: boolean26}2728interface LeaderboardRankingsProps extends React.HTMLAttributes<HTMLDivElement> {29 rankings: LeaderboardRankingItem[]30 onUserClick?: (ranking: LeaderboardRankingItem) => void31 currentUserId?: string32 showPagination?: boolean33 defaultPageSize?: 10 | 25 | 50 | 10034}3536const crownColorMap = {37 1: "text-rank-1",38 2: "text-rank-2",39 3: "text-rank-3",40} as const4142const pageSizeOptions = [10, 25, 50, 100] as const4344type LeaderboardRow =45 | { type: "ranking"; ranking: LeaderboardRankingItem }46 | { type: "ellipsis"; key: string }4748function formatLeaderboardValue(value: number) {49 if (value >= 1000000) return `${(value / 1000000).toFixed(1)}m`50 if (value >= 1000) return `${(value / 1000).toFixed(1)}k`51 return value.toLocaleString()52}5354const LeaderboardRankings = React.forwardRef<55 HTMLDivElement,56 LeaderboardRankingsProps57>(58 (59 {60 className,61 rankings,62 onUserClick,63 currentUserId,64 showPagination = false,65 defaultPageSize = 10,66 ...props67 },68 ref69 ) => {70 const [pageSize, setPageSize] = React.useState<10 | 25 | 50 | 100>(71 defaultPageSize72 )73 const [currentPage, setCurrentPage] = React.useState(1)7475 const totalPages = Math.max(1, Math.ceil(rankings.length / pageSize))7677 React.useEffect(() => {78 setCurrentPage(1)79 }, [pageSize])8081 React.useEffect(() => {82 if (currentPage > totalPages) {83 setCurrentPage(totalPages)84 }85 }, [currentPage, totalPages])8687 const pagedRankings = showPagination88 ? rankings.slice((currentPage - 1) * pageSize, currentPage * pageSize)89 : rankings9091 const rows = React.useMemo<LeaderboardRow[]>(() => {92 const nextRows: LeaderboardRow[] = []93 let hiddenRunCount = 09495 pagedRankings.forEach((ranking, index) => {96 const isDisplayed = ranking.displayed !== false97 if (!isDisplayed) {98 hiddenRunCount += 199 return100 }101102 if (hiddenRunCount > 0) {103// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from trophy
All 18 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Achievement Badgeachievement-badge | trophy | Components | Free | 1 dep | |
| Achievement Cardachievement-card | trophy | Components | Free | no deps | |
| Achievement Gridachievement-grid | trophy | Components | Free | 2 deps | |
| Achievement Listachievement-list | trophy | Components | Free | 2 deps | |
| Achievement Unlockedachievement-unlocked | trophy | Components | Free | 1 dep | |
| Leaderboard Cardleaderboard-card | trophy | Components | Free | no deps | |
| Leaderboard Podiumleaderboard-podium | trophy | Components | Free | 2 deps | |
| Points Awardspoints-awards | trophy | Components | Free | 2 deps |
