Achievement Unlocked
trophy/achievement-unlockedFreeComponent
Celebratory React dialog for newly unlocked achievements with headline, badge, and share actions. Use for unlock moments, level up animations and more. 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/achievement-unlocked.jsonSource
1"use client"23import * as React from "react"4import { CalendarDays, Share2, X } from "lucide-react"56import { cn } from "@/lib/utils"7import {8 AchievementBadge,9 type UserAchievement,10} from "@/components/ui/achievement-badge"11import { Button } from "@/components/ui/button"1213// Types (inlined - only fields used by this component)14interface Achievement {15 id: string16 name: string17 trigger?: "metric" | "api" | "streak"18 description?: string | null19 unlockedAt?: string20}2122// Props23interface AchievementUnlockedProps {24 /** Achievement that was unlocked */25 achievement: Achievement26 /** Control open state */27 open: boolean28 /** Callback when open state changes */29 onOpenChange: (open: boolean) => void30 /** Label for the secondary action button */31 secondaryActionLabel?: string32 /** Callback for the secondary action button (e.g. social share) */33 onSecondaryActionClick?: () => void34 /** @deprecated Use onSecondaryActionClick instead */35 onShare?: () => void36 /** Custom class for the dialog */37 className?: string38}3940const AchievementUnlocked = React.forwardRef<41 HTMLDivElement,42 AchievementUnlockedProps43>(44 (45 {46 achievement,47 open,48 onOpenChange,49 secondaryActionLabel = "Share",50 onSecondaryActionClick,51 onShare,52 className,53 },54 ref55 ) => {56 const handleSecondaryActionClick = onSecondaryActionClick ?? onShare57 const unlockedDateLabel = React.useMemo(() => {58 const input = achievement.unlockedAt ?? new Date().toISOString()59 const date = new Date(input)60 if (Number.isNaN(date.getTime())) return "Earned today"61 return `Earned ${date.toLocaleDateString(undefined, {62 day: "numeric",63 month: "short",64 year: "numeric",65 })}`66 }, [achievement.unlockedAt])6768 const badgeAchievement = React.useMemo<UserAchievement>(() => {69 return {70 id: achievement.id,71 name: achievement.name,72 trigger: achievement.trigger ?? "streak",73 achievedAt: achievement.unlockedAt ?? new Date().toISOString(),74 }75 }, [achievement])7677 // Handle escape key78 React.useEffect(() => {79 if (!open) return8081 const handleEscape = (e: KeyboardEvent) => {82 if (e.key === "Escape") {83 onOpenChange(false)84 }85 }8687 document.addEventListener("keydown", handleEscape)88 return () => document.removeEventListener("keydown", handleEscape)89 }, [open, onOpenChange])9091// … 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 | |
| Leaderboard Cardleaderboard-card | trophy | Components | Free | no deps | |
| Leaderboard Podiumleaderboard-podium | trophy | Components | Free | 2 deps | |
| Leaderboard Rankingsleaderboard-rankings | trophy | Components | Free | 2 deps | |
| Points Awardspoints-awards | trophy | Components | Free | 2 deps |
