webdevpuneet.com

Budget Tracker Card — Spending by Category HTML/CSS/JS

Budget Tracker Card · Dashboards · Plain HTML, CSS & JS · Live preview

CategoryDashboards

Copy & paste

Source Code

<div class="bt-card">
  <div class="bt-head">
    <div>
      <h3>Monthly budget</h3>
      <p>June 2026</p>
    </div>
    <div class="bt-total">
      <span id="btSpent">$0</span> <span class="bt-of">of $2,400</span>
    </div>
  </div>

  <div class="bt-overall">
    <div class="bt-overall-track"><div class="bt-overall-fill" id="btOverallFill"></div></div>
    <span class="bt-overall-label" id="btOverallLabel"></span>
  </div>

  <div class="bt-cats" id="btCats"></div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), 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

Single data array drives the whole card
Every bar, label, and color comes from CATEGORIES and BUDGET_CAP — no per-field DOM updates to maintain.
Three-state overall progress bar
Indigo under 80%, amber from 80–100%, red once over — both the fill color and the label text change.
Independent per-category over-budget flag
A category can flag red even while the overall total is healthy, matching how real budgets actually behave.
Capped fill width
Math.min(100, …) prevents an over-budget bar from visually overflowing its track.
Automatic remaining/over-budget label
The label text itself switches wording based on whether you're under or over, not just the color.
Color-coded category dots
Each category has its own accent color, carried through to its dot and progress fill for quick scanning.
Smooth width-only transitions
Bar fills animate via width with a cubic-bezier ease — stable in every export target since the track size never changes.
Currency formatting
Totals use toLocaleString() for comma-separated thousands, reading like real currency instead of a raw number.

About this UI Snippet

Budget Tracker Card — Overall Progress, Per-Category Caps & Over-Budget Warnings

Screenshot of the Budget Tracker Card snippet rendered live

A budget tracker only earns trust if it's honest about overspending — a green bar that quietly turns red is far more useful than a generic progress indicator. This snippet builds a monthly budget card with an overall spend bar that shifts from indigo to amber to red as it fills, plus a per-category breakdown that flags any category individually over its own cap, all driven by one small data array.

One data array drives everything

CATEGORIES is a plain array of { name, color, spent, cap } objects, and BUDGET_CAP is the single overall monthly limit. render() sums every category's spent for the total, computes the overall percentage against BUDGET_CAP, and rebuilds the category list — so updating a single number anywhere in the data instantly recomputes the whole card with one function call, no manual DOM bookkeeping per field.

Three-state overall bar

The top progress bar's fill width is the spend percentage capped at 100% (so an over-budget month doesn't overflow the track), and its color escalates through three CSS classes: the default indigo-to-purple gradient under 80% used, an amber-to-orange .warn gradient from 80–100%, and a red .over gradient once total spend exceeds the cap. The label beneath switches wording too — "$X left this month" while under budget, "$X over budget" once it isn't — so the message matches the math instead of always reading as a vague percentage.

Per-category caps, independent of the overall total

Each category has its own cap, and a category can go over its own cap (shown in red, with the row's amount text turning red via an .over class) even while the *overall* budget is still healthy — exactly how real budgeting works: groceries can run over while the month as a whole is fine because other categories came in under. This nuance is what makes a per-category breakdown more useful than a single combined bar.

Smooth, export-safe fills

Every bar fill transitions only its width with a cubic-bezier ease — width transitions on a fixed-height track are stable in every export target because the track's own dimensions never change, only the inner fill's width, so there's no layout-shift risk the way animating a container's height would have.

Connecting real transaction data

The numbers here are static placeholders meant to demonstrate the visual states; a production budget tracker sums real transactions grouped by category, typically from a bank-linking API (Plaid and similar providers) or a manually logged expense table. Because every visual — bar width, color, and label wording — is recomputed from CATEGORIES and BUDGET_CAP inside a single render() call, swapping the data source is a one-line change: replace the static spent values with a sum of that period's transactions per category, call render() again, and the card's entire visual state (including which categories flip to the over-budget red) updates correctly with no other code to touch.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA budget card renders with an overall progress bar and five category rows (Groceries, Dining, Transport, Entertainment, Shopping).
  2. 2
    Read the overall barIts color and the label beneath show whether you're under budget, in the 80%+ warning zone, or over for the month.
  3. 3
    Check each categoryCategories over their own cap show in red even if the overall budget is still healthy — read each row independently.
  4. 4
    Edit the dataChange any spent or cap value in the CATEGORIES array, or BUDGET_CAP, and call render() to see every bar and label recompute.
  5. 5
    Add or remove categoriesPush or remove an object in CATEGORIES — the category list and overall total both adjust automatically.
  6. 6
    Connect real transaction dataReplace the static spent values with a sum of your transaction API's amounts grouped by category, then call render() after each fetch.

Real-world uses

Common Use Cases

Personal finance dashboards
The core "how am I doing this month" card for budgeting apps — pair with a pomodoro timer or habit widgets for a full personal dashboard.
Expense management tools
Show team or department spend against allocated category budgets in an internal finance tool.
Subscription and SaaS usage limits
Repurpose the per-category bars for usage-vs-quota tracking (API calls, storage, seats) instead of money.
Banking and fintech apps
A familiar, trustworthy spend-tracking card for a bank or budgeting app's home screen.
Project budget tracking
Use categories as project line items (materials, labor, contingency) instead of personal spending categories.
Learning data-driven progress UI
A clean example of deriving every visual state (color, width, label) from a small data model — compare with a gradient progress bar for a simpler single-value case.
Related: Database Connection Pool Monitor Tile
See the Database Connection Pool Monitor Tile for a related dashboards pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Fetch your transactions, group and sum them by category into the same { name, color, spent, cap } shape used by CATEGORIES, assign the result to CATEGORIES, and call render() — every bar, label, and color recomputes from the new totals.

Edit the thresholds in render(): the ".warn" class is added when pct > 80, and ".over" when totalSpent > BUDGET_CAP — change 80 to whatever warning threshold fits your use case.

Add an input bound to BUDGET_CAP (or each category's cap) and call render() on change — the existing percentage math and color thresholds will reflect the new limit immediately.

The card has no built-in time period logic — it just compares spent against cap. Swap BUDGET_CAP and the category caps for your daily/weekly limits, and update the header text ("June 2026") to match your period.

In React, keep categories and budgetCap in state and compute percentages with useMemo, rendering rows with .map(); in Vue, use a computed categories array with v-for; in Angular, use *ngFor with a getter for percentages. The color-threshold logic ports directly into each framework's conditional class binding.