← Component Library
Gamification Components

Gamification Patterns

Motivating touches that reward progress — daily challenges, streaks, and certificates. Each with a live demo and the HTML & CSS.

01 · Daily Challenge

A fresh task each day

A card presenting today's challenge with a single clear action. Daily goals bring people back — keep it small and achievable.

Today's Challenge

Build a responsive card with Flexbox.

HTML

<div class="challenge">
  <i class="ph ph-target"></i>
  <h4>Today's Challenge</h4>
  <p>Build a responsive card with Flexbox.</p>
  <button>Start — +50 XP</button>
</div>

CSS

.challenge {
  border: 1px solid #e5e7eb; border-radius: 14px;
  padding: 18px; text-align: center; max-width: 340px;
}
.challenge button { background: #38bdf8; color: #fff; border: none;
                    border-radius: 8px; padding: 10px 18px; }
02 · Streak Tracker

Keep the chain going

A row of day markers showing completed days, today, and upcoming — plus a streak count. Visible progress is a strong motivator.

MTW TFSS
3-day streak

HTML

<div class="streak">
  <span class="day done">M</span>
  <span class="day done">T</span>
  <span class="day done">W</span>
  <span class="day today">T</span>
  <span class="day">F</span>
  <span class="day">S</span>
  <span class="day">S</span>
  <span class="flame"><i class="ph ph-fire-fill"></i> 3-day streak</span>
</div>

CSS

.day {
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  background: #e5e7eb; color: #6b7280;
}
.day.done  { background: #22c55e; color: #fff; }   /* completed */
.day.today { background: #38bdf8; color: #fff; }   /* current  */
03 · Completion Certificate

Reward the finish line

A certificate marks a milestone — a course finished, a level cleared. A double border, a seal, and a serif headline give it that “official” feel.

Certificate of Completion

Web Design Foundations

Jordan Parker

has successfully completed the course — May 2026

HTML

<div class="certificate">
  <div class="seal"><i class="ph ph-seal-check"></i></div>
  <p class="kicker">Certificate of Completion</p>
  <h3>Web Design Foundations</h3>
  <p class="name">Jordan Parker</p>
  <p>has successfully completed the course — May 2026</p>
</div>

CSS

.certificate {
  border: 3px double #c9a227;     /* classic double border */
  border-radius: 12px;
  padding: 26px; text-align: center;
  background: #fffdf5;
}
.certificate h3 { font-family: Georgia, serif; }
.certificate .name { border-bottom: 2px solid #c9a227; }
More gamification looks — XP, badges, levels, leaderboards — live on the Gamified Design page.
04 · Badge System

Earnable badges in tiers

Badges reward specific accomplishments. Use tiers (bronze / silver / gold) and show locked ones greyed-out so people see what's next to earn.

First Site
Gold
Stylist
Silver
First Code
Bronze
Deploy Pro
Locked

HTML

<div class="gm-badges">
  <div class="gm-badge gold"><div class="gm-medal"><div class="disc"><i class="ph ph-trophy-fill"></i></div></div><div class="nm">First Site</div><div class="lv">Gold</div></div>
  <div class="gm-badge silver"><div class="gm-medal"><div class="disc"><i class="ph ph-paint-brush-fill"></i></div></div><div class="nm">Stylist</div><div class="lv">Silver</div></div>
  <div class="gm-badge bronze"><div class="gm-medal"><div class="disc"><i class="ph ph-code-fill"></i></div></div><div class="nm">First Code</div><div class="lv">Bronze</div></div>
  <div class="gm-badge locked"><div class="gm-medal"><div class="disc"><i class="ph ph-lock-fill"></i></div></div><div class="nm">Deploy Pro</div><div class="lv">Locked</div></div>
</div>
<!-- Load Phosphor icons in <head>: -->
<!-- <script src="https://unpkg.com/@phosphor-icons/web"></script> -->

CSS — starburst “merit seal” shape with ribbon

.gm-badges { display: flex; gap: 24px; flex-wrap: wrap; }
.gm-badge { text-align: center; width: 96px; }
.gm-medal { position: relative; width: 78px; height: 78px; margin: 0 auto 8px; }
/* the ribbon tails behind the seal */
.gm-medal::before, .gm-medal::after { content: ""; position: absolute; bottom: -16px;
  width: 16px; height: 30px; background: var(--ribbon, #94a3b8); z-index: 0; }
.gm-medal::before { left: 24px; transform: rotate(8deg);
  clip-path: polygon(0 0,100% 0,100% 100%,50% 78%,0 100%); }
.gm-medal::after  { right: 24px; transform: rotate(-8deg);
  clip-path: polygon(0 0,100% 0,100% 100%,50% 78%,0 100%); }
.gm-badge .disc { position: relative; z-index: 1; width: 78px; height: 78px;
  display: grid; place-items: center; font-size: 1.8rem; color: #fff;
  transition: transform .25s;
  clip-path: polygon(50% 0,61% 12%,77% 7%,79% 24%,95% 27%,87% 42%,100% 50%,87% 58%,
    95% 73%,79% 76%,77% 93%,61% 88%,50% 100%,39% 88%,23% 93%,21% 76%,5% 73%,
    13% 58%,0 50%,13% 42%,5% 27%,21% 24%,23% 7%,39% 12%); }
/* inner ring for the classic seal look */
.gm-badge .disc::after { content: ""; position: absolute; inset: 16px;
  border-radius: 50%; border: 2px solid rgba(255,255,255,.5); }
.gm-badge .disc > i { position: relative; z-index: 1;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,.4)); }
.gm-badge:hover .disc { transform: rotate(10deg) scale(1.06); }
.gm-badge.gold   .disc { background: radial-gradient(circle at 36% 28%, #fff7d6, #f5b942 52%, #b8780a); }
.gm-badge.gold   { --ribbon: #d97706; }
.gm-badge.silver .disc { background: radial-gradient(circle at 36% 28%, #ffffff, #cfd4da 52%, #8a9099); }
.gm-badge.silver { --ribbon: #94a3b8; }
.gm-badge.bronze .disc { background: radial-gradient(circle at 36% 28%, #ffd9a8, #d98c3f 52%, #8a4f16); }
.gm-badge.bronze { --ribbon: #b45309; }
.gm-badge.locked .disc { background: #e2e5ea; color: #b0b6bf; }
.gm-badge.locked { --ribbon: #cbd5e1; }
.gm-badge.locked .disc::after { border-color: rgba(255,255,255,.7); }
.gm-badge .nm { font-size: .76rem; font-weight: 700; color: #374151; }
.gm-badge .lv { font-size: .66rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; }
.gm-badge.gold   .lv { color: #b45309; }
.gm-badge.silver .lv { color: #6b7280; }
.gm-badge.bronze .lv { color: #92400e; }
.gm-badge.locked .lv { color: #9ca3af; }
05 · Achievement System

Pop-up when something's unlocked

An achievements panel tracks what's earned, what's in progress, and what's still locked — each row shows an icon, description, and status. The pop-up toast is the celebration moment when one unlocks; click “Complete a lesson” to see it fire.

First Steps
Completed your first lesson
Unlocked
On a Roll
Study 3 days in a row — 2 of 3
66%
Site Launcher
Deploy your first project
Locked

HTML — an achievement row, the button, and the toast

<div class="achievement unlocked">
  <div class="icon"><i class="ph ph-medal-fill"></i></div>
  <div><p class="title">First Steps</p><p>Completed your first lesson</p></div>
  <span class="status">Unlocked</span>
</div>

<div class="achievement progress"> …
  <div class="bar"><i style="width:66%"></i></div>   <!-- in-progress -->
</div>

<button id="unlockBtn">Complete a lesson</button>

<!-- the celebration toast, hidden until something unlocks -->
<div class="toast" id="toast" style="display:none">
  <div class="icon"><i class="ph ph-medal-fill"></i></div>
  <div><p class="title">Achievement Unlocked!</p><p>Finished your first lesson — +100 XP</p></div>
</div>

JavaScript — fire the toast on unlock

// Grab the button and the toast by the ids in the HTML above.
const btn   = document.getElementById('unlockBtn');
const toast = document.getElementById('toast');
let timer;

btn.addEventListener('click', () => {
  toast.style.display = 'flex';                 // celebrate
  clearTimeout(timer);                          // reset any pending hide
  timer = setTimeout(() => {
    toast.style.display = 'none';               // auto-hide after 4s
  }, 4000);
});

CSS — the locked / in-progress / unlocked states + the toast

.achievement { display: flex; align-items: center; gap: 14px; background: #fff;
  border: 1px solid #e5e7eb; border-radius: 12px; padding: 12px 14px; }
.achievement .icon { width: 44px; height: 44px; border-radius: 10px; display: grid; place-items: center; }
.achievement.unlocked .icon { background: #dcfce7; color: #16a34a; }   /* earned */
.achievement.progress .icon { background: #e0f2fe; color: #0284c7; }   /* in progress */
.achievement.locked   .icon { background: #f1f5f9; color: #cbd5e1; }   /* not yet */
.achievement .status { font-size: .7rem; font-weight: 700; padding: 4px 9px; border-radius: 999px; }
.bar   { background: #e5e7eb; border-radius: 999px; height: 6px; overflow: hidden; }
.bar i { display: block; height: 100%; background: #0284c7; }          /* in-progress fill */

#unlockBtn { background: #38bdf8; color: #fff; border: none; border-radius: 8px;
  padding: 10px 18px; font-weight: 700; cursor: pointer; margin-top: 14px; }

/* the celebration toast */
.toast { display: flex; align-items: center; gap: 14px; margin-top: 14px; max-width: 360px;
  background: #1f2433; color: #fff; border-radius: 12px; padding: 14px 18px; border-left: 4px solid #f59e0b; }
.toast .icon { width: 42px; height: 42px; border-radius: 50%; background: #f59e0b;
  display: grid; place-items: center; font-size: 1.3rem; color: #1a1205; flex: 0 0 auto; }
.toast .title { font-weight: 700; font-size: .92rem; }
Difference from badges: the achievements panel shows the full set with locked / in-progress / unlocked states; a badge is the permanent award; the toast is the brief moment of celebration when one is earned.
06 · XP Points

Points that accumulate

Experience points give every action a visible reward. Click to earn XP and watch the bar toward the next level fill.

Level 3400 / 1000 XP

HTML

<div class="xp">
  <div class="top">
    <span class="lvl">Level 3</span>
    <span class="pts"><b id="xpNow">400</b> / 1000 XP</span>
  </div>
  <div class="bar"><div class="fill" id="xpFill" style="width:40%"></div></div>
  <button id="xpBtn">+50 XP</button>
</div>

JavaScript

// Grab the button, the fill bar, and the points label by their ids.
const btn   = document.getElementById('xpBtn');
const fill  = document.getElementById('xpFill');
const label = document.getElementById('xpNow');
let xp = 400;
const max = 1000;

btn.addEventListener('click', () => {
  xp = Math.min(xp + 50, max);                  // earn 50, capped at max
  fill.style.width = (xp / max * 100) + '%';    // grow the bar
  label.textContent = xp;                       // update the number
});

CSS

.xp .top { display: flex; justify-content: space-between; align-items: baseline; }
.lvl  { font-weight: 800; }
.bar  { background: #e5e7eb; border-radius: 999px; height: 14px; overflow: hidden; }
.fill { height: 100%; width: 40%; background: linear-gradient(90deg,#38bdf8,#22c55e); transition: width .4s; }
.xp button { background: #38bdf8; color: #fff; border: none; border-radius: 8px; padding: 9px 16px; font-weight: 700; cursor: pointer; }
07 · Progress Bar

Show how far along they are

A labelled bar that fills toward a goal — for course completion, profile setup, or onboarding. The fill width is the only thing that changes.

Course progress70% complete

HTML & CSS

<div class="top"><span class="lvl">Course progress</span><span class="pts">70% complete</span></div>
<div class="bar"><div class="fill" style="width:70%"></div></div>

.top { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.lvl { font-weight: 800; color: #111; }
.pts { font-size: .82rem; color: #6b7280; }
.bar { background: #e5e7eb; border-radius: 999px; height: 14px; overflow: hidden; }
.fill { height: 100%; background: linear-gradient(90deg,#38bdf8,#22c55e); transition: width .4s; }
For a semantic version, use the native <progress value="70" max="100"></progress> element — screen readers announce it automatically.
08 · Level System

Stages that unlock in order

Levels group progress into named stages. Completed levels lock in, the current one is highlighted, and future ones stay dim.

1
2
3
4
5

HTML

<div class="levels">
  <div class="level done">1</div>
  <div class="level done">2</div>
  <div class="level cur">3</div>
  <div class="level">4</div>
  <div class="level">5</div>
</div>

CSS

.level { width: 46px; height: 46px; border-radius: 12px; display: grid; place-items: center;
         background: #e5e7eb; color: #9ca3af; font-weight: 800; }
.level.done { background: #22c55e; color: #fff; }                         /* cleared */
.level.cur  { background: #38bdf8; color: #fff; box-shadow: 0 0 0 3px rgba(56,189,248,.3); }
09 · Quiz Challenge

Answer to earn points

A timed-feel quiz where a correct answer awards XP. Pick an answer.

Which unit scales with the root font size?

HTML

<div class="quiz" id="quiz">
  <p class="q">Which unit scales with the root font size?</p>
  <button class="opt" data-correct="false">px</button>
  <button class="opt" data-correct="true">rem</button>
  <button class="opt" data-correct="false">vh</button>
  <div class="res" hidden></div>
</div>

JavaScript

// Grab the quiz container and its result line.
const quiz   = document.getElementById('quiz');
const result = quiz.querySelector('.res');

// Wire up every option button.
quiz.querySelectorAll('.opt').forEach(opt => {
  opt.addEventListener('click', () => {
    if (quiz.dataset.done) return;              // only answer once
    const right = opt.dataset.correct === 'true';
    opt.classList.add(right ? 'correct' : 'wrong');
    // If they missed, highlight the real answer too.
    if (!right) quiz.querySelector('.opt[data-correct="true"]').classList.add('correct');
    quiz.dataset.done = '1';
    result.hidden = false;
    result.textContent = right
      ? '+25 XP — correct!'
      : 'No points — the answer is highlighted.';
  });
});

CSS

.opt { display: block; width: 100%; text-align: left; background: #fff;
  border: 1px solid #cbd5e1; border-radius: 8px; padding: 10px 14px; margin: 6px 0; cursor: pointer; }
.opt:hover   { border-color: #38bdf8; }
.opt.correct { background: #dcfce7; border-color: #22c55e; color: #166534; }   /* right answer */
.opt.wrong   { background: #fee2e2; border-color: #ef4444; color: #991b1b; }   /* wrong answer */
.res { margin-top: 8px; font-weight: 700; }
10 · Leaderboard

Rank players against each other

A ranked list with position, avatar, name, and score. Highlight the current user's row so they can find themselves instantly.

1
AR
Ava R.
2,480
2
JL
Jordan L.
2,310
3
YOU
You
2,090
4
MK
Mia K.
1,870

HTML

<div class="gm-lb">
  <div class="row"><div class="rk">1</div><div class="av">AR</div><div class="nm">Ava R.</div><div class="sc">2,480</div></div>
  <div class="row"><div class="rk">2</div><div class="av">JL</div><div class="nm">Jordan L.</div><div class="sc">2,310</div></div>
  <div class="row me"><div class="rk">3</div><div class="av">YOU</div><div class="nm">You</div><div class="sc">2,090</div></div>
  <div class="row"><div class="rk">4</div><div class="av">MK</div><div class="nm">Mia K.</div><div class="sc">1,870</div></div>
</div>

CSS — highlight the user, gold for first place

.gm-lb { max-width: 420px; background: #fff; border: 1px solid #e5e7eb;
         border-radius: 12px; overflow: hidden; }
.gm-lb .row { display: flex; align-items: center; gap: 12px; padding: 11px 16px;
              border-bottom: 1px solid #f1f5f9; }
.gm-lb .row:last-child { border-bottom: none; }
.gm-lb .row.me { background: #eff6ff; }                       /* "you" stand out */
.gm-lb .rk { width: 26px; font-weight: 800; color: #9ca3af; text-align: center; }
.gm-lb .row:nth-child(1) .rk { color: #d97706; }              /* gold for first place */
.gm-lb .av { width: 32px; height: 32px; border-radius: 50%; background: #38bdf8;
             color: #fff; display: grid; place-items: center; font-weight: 700; font-size: .8rem; }
.gm-lb .nm { flex: 1; color: #374151; font-weight: 600; font-size: .9rem; }
.gm-lb .sc { font-weight: 800; color: #111; }
11 · Rewards Screen

Celebrate the payoff

A full-moment reward screen after a big milestone — a burst, the prize, and a single button to continue. Keep it brief and joyful.

Level Complete!

You finished the Flexbox module.

+200 XP Stylist Badge

HTML

<div class="reward">
  <div class="burst"><i class="ph ph-confetti"></i></div>
  <h3>Level Complete!</h3>
  <p>You finished the Flexbox module.</p>
  <div class="loot">
    <span>+200 XP</span>
    <span><i class="ph ph-medal-fill"></i> Stylist Badge</span>
  </div>
  <button>Continue</button>
</div>

CSS

.reward {
  text-align: center; border-radius: 16px; padding: 28px 22px;
  background: radial-gradient(circle at top, #fef3c7, #fff);  /* warm glow */
  border: 1px solid #fcd34d;
}
.loot span { background: #fde68a; color: #92400e; border-radius: 8px; padding: 6px 12px; }
12 · Related

Keep building

See Gamified Design and Microinteractions — or browse the full Component Library.