webdevpuneet.com

Streak Tracker — Habit Streak HTML CSS JS Snippet

Streak Tracker · Dashboards · Plain HTML, CSS & JS · Live preview

CategoryDashboards

Copy & paste

Source Code

<div class="st-card">
  <div class="st-hero">
    <div class="st-flame" id="stFlame">🔥</div>
    <div class="st-count"><span id="stStreak">12</span> day streak</div>
    <div class="st-sub">Keep it going — check in every day</div>
  </div>

  <div class="st-week">
    <div class="st-day done"><span class="st-dot"></span><em>M</em></div>
    <div class="st-day done"><span class="st-dot"></span><em>T</em></div>
    <div class="st-day done"><span class="st-dot"></span><em>W</em></div>
    <div class="st-day today"><span class="st-dot"></span><em>T</em></div>
    <div class="st-day"><span class="st-dot"></span><em>F</em></div>
    <div class="st-day"><span class="st-dot"></span><em>S</em></div>
    <div class="st-day"><span class="st-dot"></span><em>S</em></div>
  </div>

  <div class="st-stats">
    <div class="st-stat"><span id="stBest">21</span><small>Best streak</small></div>
    <div class="st-stat"><span id="stTotal">148</span><small>Total days</small></div>
  </div>

  <button class="st-btn" id="stBtn" onclick="checkIn()">Check in today</button>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Three-state week row
Dots render as completed (flame gradient), today (pulsing outline), or upcoming (muted) — instant at-a-glance progress.
Guarded one-tap check-in
A checked flag makes checkIn fire once, converting today to done and locking the button, like real streak apps.
Spring flame pop
Checking in replays a cubic-bezier scale+rotate keyframe on the flame via a forced-reflow restart — the reward moment.
Pure-CSS today pulse
The current day's attention ring is a looping box-shadow keyframe — zero JS cost and perfectly steady.
Live streak + total
Check-in increments the streak and total counters together and updates the hero number beside the flame.
Best-streak record
The best stat updates automatically whenever the current streak surpasses it — a target to beat.
Variable-driven state
streak, best, total, and checked hold all state, so seeding from a backend is a few assignments.
Premium dark styling
A gradient card with a glowing flame and orange accents gives the streak the rewarding, game-like feel it needs.

About this UI Snippet

Streak Tracker — Flame Counter, 7-Day Check-In Row & One-Tap Daily Check-In

Screenshot of the Streak Tracker snippet rendered live

Streaks are one of the most powerful engagement mechanics in apps — Duolingo, Snapchat, and fitness trackers all use them because the fear of breaking a run keeps people coming back daily. A streak tracker shows the current run, a visual week of check-ins, and a single action to extend it. This snippet implements that in plain HTML, CSS, and vanilla JavaScript: an animated flame counter, a seven-day dot row with completed/today/upcoming states, best and total stats, and a check-in button that extends the streak with a satisfying flame pop.

The week row: three day states

The seven dots represent the current week. Completed days (.done) show a filled orange gradient with a tiny flame and a coloured label; today (.today) is an outlined dot with a continuous pulsing ring drawing attention to the action; upcoming days stay muted. This instantly communicates "you've done Mon–Wed, today is Thursday, here's the rest of the week" — the at-a-glance progress that makes streaks motivating.

One-tap check-in

checkIn is guarded so it only fires once: it converts today's dot from the pulsing today state to a completed done flame, increments the streak and total counters, updates the best streak if the new run exceeds it, and disables the button to "Checked in today ✓". A checked flag prevents double check-ins, mirroring how real streak apps lock the action until the next day.

Flame celebration

The moment you check in, the big flame plays a spring st-pop keyframe — scaling up with a slight rotation and settling back via a cubic-bezier overshoot. It is re-triggered with the remove-class / force-reflow / add-class pattern so it fires on every check-in. That little reward is the dopamine hit that reinforces the habit. The today dot's pulse is a pure-CSS box-shadow animation, so it costs nothing and never drifts.

Stats that frame the streak

Best streak and total days sit below the week, giving context — a personal record to beat and a sense of long-term commitment. The current streak is the hero number beside the flame, in the accent colour.

Everything is driven by a few variables (streak, best, total, checked), so wiring it to real data is just seeding those from your backend and persisting the check-in. In production you would also reset the streak to zero if a day was missed (compare last-check-in date to today). Pair this with a profile completion meter for onboarding, an activity heatmap for long-term history, or a stats card for other metrics.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA streak card appears with a flame, "12 day streak", a week row (Mon–Wed completed, Thursday pulsing), best/total stats, and a check-in button.
  2. 2
    Read the weekCompleted days show filled flame dots, today pulses with an outlined ring, and upcoming days stay muted.
  3. 3
    Check inClick "Check in today" — today's dot fills with a flame, the streak ticks to 13, total updates, and the big flame pops.
  4. 4
    See the button lockThe button disables to "Checked in today ✓" so you cannot check in twice in one day.
  5. 5
    Watch best updateIf your new streak beats the record, the "Best streak" stat updates to match.
  6. 6
    Wire real dataSeed streak, best, and total from your backend and persist the check-in date; reset the streak if a day is missed.

Real-world uses

Common Use Cases

Habit and learning apps
Daily check-ins for language, fitness, or study apps. Pair with a profile completion meter during onboarding.
Engagement and retention
Reward daily logins or actions in any product; combine with an activity heatmap for the full history.
Fitness and wellness
Workout, meditation, or water-intake streaks where the flame and week row drive consistency.
Productivity and journaling
Daily writing, todo, or focus-session streaks; sits well in a dashboard layout.
Gamified communities
Forum or community daily-visit streaks alongside a leaderboard table for competition.
Finance and savings
No-spend or daily-saving streaks, reframing a habit goal with the same motivating mechanic.

Got questions?

Frequently Asked Questions

Store the streak, best, total, and the last check-in date (server-side or in localStorage). On load, compare today to the last check-in: if it is the next day, allow check-in; if more than one day has passed, reset the streak to 0 before rendering. Save the new values after each check-in. This date logic is what makes a streak real rather than a counter.

Render more dots (a 30-day grid) or switch to an activity heatmap for a calendar view. Keep the seven-day row as the focused "this week" widget and link to the fuller history — most apps show both: a compact current week and an expandable full calendar.

Always validate check-ins server-side against the user's stored timezone (or UTC day boundaries), not the client clock, since device time can be changed. The client UI is optimistic, but the authoritative streak count and the "already checked in today" rule must be enforced on the server.

Make the check-in a real <button> (it is) so it is keyboard-operable, and announce the new streak via an aria-live="polite" region after check-in. Give each day dot an aria-label ("Monday: completed", "Thursday: today") since the state is conveyed by colour and a flame glyph; ensure the disabled state is communicated, not just styled.

In React, hold streak, best, total, and checkedToday in useState, render the week from a days array, and trigger the flame pop by toggling a class/key on check-in. In Vue, use refs and :class bindings with a method. In Angular, track state on the component and bind [class.done]/[disabled]. The pop/pulse keyframes port unchanged.