@use 'sprucecss/scss/spruce' as *;
.activity-heatmap {
--activity-heatmap-cell: 1.125rem;
--activity-heatmap-gap: 3px;
background-color: color('surface');
border: config('border-width-base', $display) solid color('border');
border-radius: radius('lg');
margin: 0;
padding: spacer('m');
@include layout-stack('s');
&__caption {
display: flex;
flex-wrap: wrap;
gap: spacer('xxs') spacer('xs');
justify-content: space-between;
}
&__title {
color: color('heading');
font-weight: 700;
}
&__subtitle {
color: color('muted');
font-size: config('font-size-sm', $typography);
}
&__scroll {
overflow-x: auto;
&:focus-visible {
outline: 2px solid color('focus-ring');
outline-offset: 2px;
}
}
&__grid {
border-collapse: separate;
border-spacing: var(--activity-heatmap-gap);
color: color('muted');
font-size: 0.75rem;
inline-size: auto;
margin: 0;
table-layout: fixed;
th,
td {
border: 0;
line-height: 1;
padding: 0;
}
thead th {
block-size: 1.25em;
font-weight: 400;
inline-size: var(--activity-heatmap-cell);
position: relative;
text-align: start;
}
abbr {
border: 0;
cursor: default;
text-decoration: none;
}
td[data-level] {
block-size: var(--activity-heatmap-cell);
}
}
&__month {
inset-block-start: 0;
inset-inline-start: 0;
position: absolute;
white-space: nowrap;
}
&__day {
font-weight: 400;
padding-inline-end: spacer('xxs') !important;
text-align: start;
&--hidden abbr {
@include visually-hidden;
}
}
&__cell,
&__grid td[data-level] {
background-color: color('surface-muted');
border-radius: radius('sm');
box-shadow: inset 0 0 0 1px color-alpha('border', 0.8);
inline-size: var(--activity-heatmap-cell);
}
&__cell,
&__grid td {
&[data-level='1'] {
background-color: color-alpha('primary', 0.25);
}
&[data-level='2'] {
background-color: color-alpha('primary', 0.5);
}
&[data-level='3'] {
background-color: color-alpha('primary', 0.75);
}
&[data-level='4'] {
background-color: color('primary');
}
}
&__legend {
align-items: center;
color: color('muted');
display: flex;
font-size: 0.75rem;
gap: var(--activity-heatmap-gap);
justify-content: flex-end;
span:first-child {
margin-inline-end: spacer('xxs');
}
span:last-child {
margin-inline-start: spacer('xxs');
}
}
&__cell {
block-size: var(--activity-heatmap-cell);
display: inline-block;
}
}
<figure class="activity-heatmap">
<figcaption class="activity-heatmap__caption">
<span class="activity-heatmap__title">Orders per day</span>
<span class="activity-heatmap__subtitle">Last 12 weeks · 785 orders</span>
</figcaption>
<div class="activity-heatmap__scroll" tabindex="0" role="region" aria-label="Orders per day, scrollable">
<table class="activity-heatmap__grid">
<caption class="sr-only">Orders per day in the last 12 weeks; the columns are the weeks, starting on Monday</caption>
<thead>
<tr>
<td></td>
<th scope="col"><span class="activity-heatmap__month">Jul</span> <span class="sr-only">13</span></th>
<th scope="col"><span class="sr-only">Jul 20</span></th>
<th scope="col"><span class="sr-only">Jul 27</span></th>
<th scope="col"><span class="activity-heatmap__month">Aug</span> <span class="sr-only">3</span></th>
<th scope="col"><span class="sr-only">Aug 10</span></th>
<th scope="col"><span class="sr-only">Aug 17</span></th>
<th scope="col"><span class="sr-only">Aug 24</span></th>
<th scope="col"><span class="sr-only">Aug 31</span></th>
<th scope="col"><span class="activity-heatmap__month">Sep</span> <span class="sr-only">7</span></th>
<th scope="col"><span class="sr-only">Sep 14</span></th>
<th scope="col"><span class="sr-only">Sep 21</span></th>
<th scope="col"><span class="sr-only">Sep 28</span></th>
</tr>
</thead>
<tbody>
<tr>
<th class="activity-heatmap__day" scope="row"><abbr title="Monday">Mon</abbr></th>
<td data-level="2"><span class="sr-only">Jul 13: 10 orders</span></td>
<td data-level="3"><span class="sr-only">Jul 20: 12 orders</span></td>
<td data-level="1"><span class="sr-only">Jul 27: 3 orders</span></td>
<td data-level="1"><span class="sr-only">Aug 3: 4 orders</span></td>
<td data-level="1"><span class="sr-only">Aug 10: 3 orders</span></td>
<td data-level="0"><span class="sr-only">Aug 17: 0 orders</span></td>
<td data-level="4"><span class="sr-only">Aug 24: 16 orders</span></td>
<td data-level="2"><span class="sr-only">Aug 31: 10 orders</span></td>
<td data-level="0"><span class="sr-only">Sep 7: 0 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 14: 22 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 21: 12 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 28: 23 orders</span></td>
</tr>
<tr>
<th class="activity-heatmap__day activity-heatmap__day--hidden" scope="row"><abbr title="Tuesday">Tue</abbr></th>
<td data-level="4"><span class="sr-only">Jul 14: 18 orders</span></td>
<td data-level="1"><span class="sr-only">Jul 21: 1 order</span></td>
<td data-level="1"><span class="sr-only">Jul 28: 2 orders</span></td>
<td data-level="1"><span class="sr-only">Aug 4: 5 orders</span></td>
<td data-level="2"><span class="sr-only">Aug 11: 6 orders</span></td>
<td data-level="4"><span class="sr-only">Aug 18: 20 orders</span></td>
<td data-level="2"><span class="sr-only">Aug 25: 8 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 1: 21 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 8: 15 orders</span></td>
<td data-level="2"><span class="sr-only">Sep 15: 6 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 22: 11 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 29: 22 orders</span></td>
</tr>
<tr>
<th class="activity-heatmap__day" scope="row"><abbr title="Wednesday">Wed</abbr></th>
<td data-level="2"><span class="sr-only">Jul 15: 10 orders</span></td>
<td data-level="3"><span class="sr-only">Jul 22: 14 orders</span></td>
<td data-level="2"><span class="sr-only">Jul 29: 8 orders</span></td>
<td data-level="2"><span class="sr-only">Aug 5: 8 orders</span></td>
<td data-level="3"><span class="sr-only">Aug 12: 11 orders</span></td>
<td data-level="3"><span class="sr-only">Aug 19: 12 orders</span></td>
<td data-level="3"><span class="sr-only">Aug 26: 12 orders</span></td>
<td data-level="1"><span class="sr-only">Sep 2: 5 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 9: 17 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 16: 14 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 23: 20 orders</span></td>
<td data-level="2"><span class="sr-only">Sep 30: 7 orders</span></td>
</tr>
<tr>
<th class="activity-heatmap__day activity-heatmap__day--hidden" scope="row"><abbr title="Thursday">Thu</abbr></th>
<td data-level="4"><span class="sr-only">Jul 16: 18 orders</span></td>
<td data-level="2"><span class="sr-only">Jul 23: 10 orders</span></td>
<td data-level="3"><span class="sr-only">Jul 30: 12 orders</span></td>
<td data-level="4"><span class="sr-only">Aug 6: 19 orders</span></td>
<td data-level="1"><span class="sr-only">Aug 13: 4 orders</span></td>
<td data-level="2"><span class="sr-only">Aug 20: 10 orders</span></td>
<td data-level="0"><span class="sr-only">Aug 27: 0 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 3: 12 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 10: 18 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 17: 16 orders</span></td>
<td data-level="0"><span class="sr-only">Sep 24: 0 orders</span></td>
<td data-level="4"><span class="sr-only">Oct 1: 19 orders</span></td>
</tr>
<tr>
<th class="activity-heatmap__day" scope="row"><abbr title="Friday">Fri</abbr></th>
<td data-level="1"><span class="sr-only">Jul 17: 3 orders</span></td>
<td data-level="2"><span class="sr-only">Jul 24: 6 orders</span></td>
<td data-level="1"><span class="sr-only">Jul 31: 5 orders</span></td>
<td data-level="3"><span class="sr-only">Aug 7: 13 orders</span></td>
<td data-level="4"><span class="sr-only">Aug 14: 17 orders</span></td>
<td data-level="4"><span class="sr-only">Aug 21: 16 orders</span></td>
<td data-level="3"><span class="sr-only">Aug 28: 11 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 4: 16 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 11: 12 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 18: 15 orders</span></td>
<td data-level="4"><span class="sr-only">Sep 25: 17 orders</span></td>
<td data-level="2"><span class="sr-only">Oct 2: 9 orders</span></td>
</tr>
<tr>
<th class="activity-heatmap__day activity-heatmap__day--hidden" scope="row"><abbr title="Saturday">Sat</abbr></th>
<td data-level="0"><span class="sr-only">Jul 18: 0 orders</span></td>
<td data-level="0"><span class="sr-only">Jul 25: 0 orders</span></td>
<td data-level="3"><span class="sr-only">Aug 1: 11 orders</span></td>
<td data-level="0"><span class="sr-only">Aug 8: 0 orders</span></td>
<td data-level="2"><span class="sr-only">Aug 15: 7 orders</span></td>
<td data-level="3"><span class="sr-only">Aug 22: 12 orders</span></td>
<td data-level="0"><span class="sr-only">Aug 29: 0 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 5: 11 orders</span></td>
<td data-level="0"><span class="sr-only">Sep 12: 0 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 19: 13 orders</span></td>
<td data-level="2"><span class="sr-only">Sep 26: 9 orders</span></td>
<td data-level="3"><span class="sr-only">Oct 3: 12 orders</span></td>
</tr>
<tr>
<th class="activity-heatmap__day activity-heatmap__day--hidden" scope="row"><abbr title="Sunday">Sun</abbr></th>
<td data-level="0"><span class="sr-only">Jul 19: 0 orders</span></td>
<td data-level="0"><span class="sr-only">Jul 26: 0 orders</span></td>
<td data-level="0"><span class="sr-only">Aug 2: 0 orders</span></td>
<td data-level="0"><span class="sr-only">Aug 9: 0 orders</span></td>
<td data-level="3"><span class="sr-only">Aug 16: 12 orders</span></td>
<td data-level="0"><span class="sr-only">Aug 23: 0 orders</span></td>
<td data-level="0"><span class="sr-only">Aug 30: 0 orders</span></td>
<td data-level="1"><span class="sr-only">Sep 6: 1 order</span></td>
<td data-level="0"><span class="sr-only">Sep 13: 0 orders</span></td>
<td data-level="2"><span class="sr-only">Sep 20: 7 orders</span></td>
<td data-level="3"><span class="sr-only">Sep 27: 12 orders</span></td>
<td data-level="3"><span class="sr-only">Oct 4: 12 orders</span></td>
</tr>
</tbody>
</table>
</div>
<div class="activity-heatmap__legend" aria-hidden="true">
<span>Less</span>
<span class="activity-heatmap__cell" data-level="0"></span>
<span class="activity-heatmap__cell" data-level="1"></span>
<span class="activity-heatmap__cell" data-level="2"></span>
<span class="activity-heatmap__cell" data-level="3"></span>
<span class="activity-heatmap__cell" data-level="4"></span>
<span>More</span>
</div>
</figure>