Nasaq
Components

Gamification

A kit for progress and rewards. Leaderboard with period tabs, podium, movement arrows and your rank pinned, a badge grid with earned, in-progress and locked states and rarity, achievement card, XP and level progress, streak counter with calendar, reward cards and an unlock toast that respects reduced motion.

PreviewOpen ↗

Code

import { BadgeGrid, Leaderboard, XpProgress } from "@fadymondy/nasaq/web";export const Page = () => (  <>    <XpProgress totalXp={1380} />    <BadgeGrid achievements={[{ id: "a", title: "First step", rarity: "common", earnedAt: "2026-09-01" }]} />    <Leaderboard entries={[{ id: "u1", name: "Layla", score: 4820, previousRank: 2 }]} youId="u1" unit="XP" />  </>);

Gamification · beta

Live examples and controls: Gamification in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/gamification.json

Generic parts for showing progress and rewards. Nothing product specific is baked in: you provide the achievements, scores and days, and the kit lays them out, ranks them and works out levels and streaks.

When to use

  • Achievements, levels, streaks, rankings and rewards in a learning, fitness, community or team app.

When not to use

  • Plain numeric progress: use Progress.
  • Tables of ranked data with sorting and filters: use DataTable.

Import

import { Leaderboard } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"

Quick start

import { BadgeGrid, Leaderboard, XpProgress } from "@fadymondy/nasaq/web";

export const Page = () => (
  <>
    <XpProgress totalXp={1380} />
    <BadgeGrid achievements={[{ id: "a", title: "First step", rarity: "common", earnedAt: "2026-09-01" }]} />
    <Leaderboard entries={[{ id: "u1", name: "Layla", score: 4820, previousRank: 2 }]} youId="u1" unit="XP" />
  </>
);

Anatomy

Leaderboard                data-slot="leaderboard": header with period Tabs, podium (2, 1, 3), ranked list, pinned "you" row
BadgeGrid                  filter Tabs (All, Earned, In progress, Locked) and a grid of AchievementMedal
AchievementCard            medal, rarity, XP, description, progress or earned date
XpProgress                 level number, XP in level, bar, XP to the next level
StreakCounter              flame, days in a row, longest, at-risk note
StreakCalendar / StreakCard month grid with active days; card combines both
RewardCard                 art, rarity, cost, Claim with progress and error states
AchievementUnlockToast     status region with a medal pop and burst

API

ComponentMain props
Leaderboardentries ({ id, name, score, previousRank?, avatar?, subtitle? }), youId, periods, period, onPeriodChange, unit, limit (10), podium (true), loading, title.
BadgeGridachievements, filters (true), filter, onFilterChange, onSelect(id), selectedId.
AchievementCardachievement, actions.
Achievement{ id, title, description?, icon?, rarity?, progress?, goal?, earnedAt?, xp?, secret? }.
XpProgresstotalXp, curve ({ base, growth }).
StreakCountercurrent, longest, atRisk.
StreakCalendar / StreakCardactiveDays, month, onMonthChange, today, weekStart.
RewardCardtitle, description, art, rarity, cost, costUnit, balance, status, lockedReason, onClaim (async, may resolve { error }).
AchievementUnlockToastachievement, open, onClose, onView, duration (6000), floating.

Rarity is common, uncommon, rare, epic or legendary. Tied scores share a rank (1, 2, 2, 4). Pure helpers, tested: rankEntries, movement, levelProgress, streakStats, monthGrid, achievementStatus.

Examples

Async claim with an error

import { RewardCard } from "@fadymondy/nasaq/web";

export const Reward = () => (
  <RewardCard title="Golden frame" cost={800} balance={1200} rarity="rare" onClaim={async () => ({ error: "Out of stock." })} />
);

Accessibility

  • Rarity, status and movement are always words as well as colour or icon (screen reader text on arrows).
  • Your row is marked aria-current. The pinned row is a labelled list.
  • The unlock toast is a polite role="status" that stays mounted, pauses its timer on hover and focus, and can be dismissed.
  • Under prefers-reduced-motion the toast is a still card: no pop and no burst.

RTL & i18n

English and Arabic follow the Nasaq locale, override with labels. Numbers use Num, the calendar starts on Saturday in Arabic, the ring fill mirrors.

Styling & tokens

Tokens only. Epic uses the violet tag hue and legendary the accent. No custom CSS: the burst uses the Web Animations API.

Do / Don't

  • Do let people see how to earn a locked badge.
  • Don't make rank the only way to feel progress: show personal progress too.
  • Don't use the celebration for routine events.

Progress, Badge, Tabs, Toast.

On this page