Leaderboard Card
trophy/leaderboard-cardFreeComponent
React leaderboard component that composes title, date range, podium, and rankings—one card for competitive gamification UIs. Fits Next.js and React apps. Built on shadcn/ui + Tailwind. Open source.
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-card.jsonSource
1"use client"23import * as React from "react"45import { cn } from "@/lib/utils"6import {7 LeaderboardPodium,8 type LeaderboardRanking as LeaderboardPodiumRanking,9} from "@/components/ui/leaderboard-podium"10import {11 LeaderboardRankings,12 type LeaderboardRankingItem,13} from "@/components/ui/leaderboard-rankings"1415interface LeaderboardRunOption {16 id: string17 label: string18}1920interface LeaderboardCardProps extends React.HTMLAttributes<HTMLDivElement> {21 title?: string22 fromDate: string | Date23 toDate: string | Date24 podiumRankings: LeaderboardPodiumRanking[]25 rankings: LeaderboardRankingItem[]26 currentUserId?: string27 runOptions?: LeaderboardRunOption[]28 selectedRunId?: string29 onRunChange?: (runId: string) => void30}3132function formatRangeDate(date: string | Date) {33 const parsed = date instanceof Date ? date : new Date(date)34 if (Number.isNaN(parsed.getTime())) return ""3536 return parsed.toLocaleDateString(undefined, {37 month: "short",38 day: "numeric",39 year: "numeric",40 })41}4243const LeaderboardCard = React.forwardRef<HTMLDivElement, LeaderboardCardProps>(44 (45 {46 className,47 title = "Leaderboard",48 fromDate,49 toDate,50 podiumRankings,51 rankings,52 currentUserId,53 runOptions,54 selectedRunId,55 onRunChange,56 ...props57 },58 ref59 ) => {60 const fromLabel = formatRangeDate(fromDate)61 const toLabel = formatRangeDate(toDate)62 const resolvedRunId = selectedRunId ?? runOptions?.[0]?.id ?? ""63 const hasOnRunChange = Boolean(onRunChange)64 const [localRunId, setLocalRunId] = React.useState(resolvedRunId)6566 React.useEffect(() => {67 if (hasOnRunChange) return68 setLocalRunId(resolvedRunId)69 }, [hasOnRunChange, resolvedRunId])7071 const activeRunId = hasOnRunChange ? resolvedRunId : localRunId7273 return (74 <div75 ref={ref}76 className={cn("bg-card rounded-2xl border p-6 shadow-sm", className)}77 {...props}78 >79 <div className="mb-6 flex items-start justify-between gap-4">80 <div className="space-y-1">81 <h3 className="text-xl font-semibold">{title}</h3>82 <p className="text-muted-foreground text-sm">83 {fromLabel} - {toLabel}84 </p>85 </div>8687 {runOptions && runOptions.length > 0 ? (88 <select89 aria-label="Select leaderboard run"90 value={activeRunId}91 onChange={(e) => {92 if (onRunChange) {93// … truncated
What it pulls in
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 Podiumleaderboard-podium | trophy | Components | Free | 2 deps | |
| Leaderboard Rankingsleaderboard-rankings | trophy | Components | Free | 2 deps | |
| Points Awardspoints-awards | trophy | Components | Free | 2 deps |
