Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

User Activity Heatmap Dashboard Block for React Aria

A week of product activity as a 7 by 24 grid you can read as activity or as the difference from a baseline, with a day you can open into hourly bars and a select for the baseline.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Find the hours your product is used more or less than usual with this user activity heatmap for React with React Aria. A hairline frame with a plus mark on each corner draws seven days by 24 hours as small squares in five solid steps of foreground. A Toggle Group switches between Activity, how busy each hour was, and Difference, how far each hour is from a baseline: a plus or a minus in each square, a darker step for a bigger gap, and diagonal hatching on the hours that fell. A Native Select in the header picks the baseline: last week, the four-week average or the same week last month. Choosing a day row opens that day's hourly bars with a tick for the baseline in each hour, and a polite line reads the day against the baseline and names its peak. A last band gives the week's total, its change and the busiest hour. It's built from Toggle Group, Native Select and Guides, with a CSS entrance only. For product analytics, support staffing and any page about when people show up.

FAQ

Where do the numbers come from?

They are generated from a seed in the file: an hourly profile for a weekday, a multiplier for each day and a little noise, so the week is the same on every load. Each baseline is the same week shifted by a typed amount, with Friday afternoons set apart so Difference has a story. Replace THIS_WEEK and BASELINES with your hourly counts and nothing else changes.

How is the difference worked out?

For each hour it is this week's actions divided by the baseline's, minus one. Gaps under 5% have no glyph, and an hour where both weeks had fewer than 10 actions counts as level so the quiet night hours don't look dramatic. A minus also hatches the square, so the sign doesn't depend on a glyph being readable on a phone.

How do I open a day?

The day names are a group of radio buttons: press one, or use the arrow keys once focus is in the list, and the band below shows that day's 24 bars with a tick for the baseline hour. Every day row also states its total and its change in its accessible name, so a screen reader doesn't need the squares.

What stays local, and how do I wire it for real?

Everything: the counts are generated and nothing is tracked. To make it real, bucket your events by hour in the timezone your team works in, build the baselines the same way, and keep the 5% and 10-action thresholds or tune them to your volume.

How does it look on a phone?

The squares stay square and shrink to fit, hour labels step by six instead of three, and the plus and minus glyphs are left out in favour of the step and the hatching. The day band and the totals stack under the grid.