Staaarter

Billing Feature Usage Heat Map

A data-dense grid showing how heavily each feature is used across a set of time buckets, such as hours of the day. Cell opacity scales against the busiest cell in the whole grid, so darker cells stand out as usage peaks at a glance. Below the sm breakpoint the grid is replaced with a ranked list of each feature's total activity and single peak period, since a dense grid doesn't read well on a phone.

By Staaarter Team
Billing
Updated July 23, 2026
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/billing-feature-usage-heat-map.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/billing/billing60.tsx instead.

Usage

The file also exports billing60Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Billing60, billing60Demo } from "@/components/blocks/billing/billing60";

export default function Page() {
  return <Billing60 {...billing60Demo} />;
}

Props

PropTypeDefaultDescription
headingstring"Feature usage heat map"Heading in the header.
descriptionstringnoneOptional supporting line under the heading.
columnLabelsstring[]noneLabels for each time bucket column, e.g. hours or days.
rowsHeatMapRow[]noneOne row per feature. Each row's values array must be the same length as columnLabels.
legendLabelstring"Events per period"Short label describing what the cell values represent.
classNamestringnoneExtra classes for the outer card.

Types

interface HeatMapRow {
  id: string;
  featureName: string;
  values: number[];
}

Behavior notes

  • Cell opacity is computed against the single highest value found anywhere in the grid (across every row and column), not per row, so intensity is comparable across features, not just within one feature's own range.
  • Zero-value cells still render at a small fixed opacity so the grid stays visible instead of leaving blank gaps.
  • Every cell carries both a native title tooltip and an aria-label spelling out the exact feature, period, and count, since color intensity alone doesn't convey the value to everyone.
  • Below the sm breakpoint the table is hidden and replaced with a list sorted by each feature's total across all periods, along with its single busiest period. Both views are computed from the same rows prop at render time.
  • There's no live or websocket wiring, drill-down click handler, or search filter built in, rows and columnLabels are plain data you pass in already aggregated.

Frequently asked questions