HeatmapChartWithYearOfDays
A headless wrapper for a year-of-days heatmap: one cell per day of one year, laid out in week columns and weekday rows, with cell colour encoding the value of each day. It specialises HeatmapChart (same shell, same data-table sibling) and adds the two facts the layout needs, year and weekStart. Use it for a per-day measure across a year, such as contributions, visits, appointments or readings per day.
Status: experimental — added 2026-10-22 from the chanhdai.com github-contributions review (chanhdai-lessons ); implemented and unit-tested in all nine headless catalogs, not yet exercised in composed flows.
The component renders a <figure> holding a <div class="heatmap-chart-with-year-of-days-graphic" role="img" aria-label> around an inline <svg> that the consumer draws, names the figure with aria-label (from label), and lets the consumer reference a longer description or a real data <table> through aria-describedby. The component draws nothing and ships no scales, colours or animation; it exists to give every chart in the catalog the same accessible, stylable shell.
Example
Activity score per month in 2026 Month Score January 75 February 50 March 32 April 34 May 51 June 63 July 77 August 56 September 34 October 30 November 48 December 63
Show demo markup <figure class="heatmap-chart-with-year-of-days" data-year="2026" data-week-start="1"><div class="heatmap-chart-with-year-of-days-graphic" role="img" aria-label="Activity per day in 2026, weeks starting on Monday"><svg viewBox="0 0 634 82" width="634" height="82" aria-hidden="true" focusable="false"><rect x="0" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="0" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="0" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="0" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="12" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="12" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="12" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="12" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="12" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="12" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="12" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="24" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="24" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="24" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="24" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="24" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="24" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="24" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="36" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="36" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="36" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="36" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="36" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="36" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="36" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="48" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="48" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="48" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="48" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="48" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="48" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="48" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="60" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="60" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="60" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="60" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="60" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="60" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="60" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="72" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="72" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="72" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="72" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="72" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="72" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="72" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="84" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="84" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="84" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="84" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="84" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="84" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="84" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="96" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="96" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="96" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="96" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="96" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="96" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="96" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="108" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="108" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="108" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="108" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="108" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="108" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="108" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="120" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="120" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="120" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="120" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="120" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="120" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="120" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="132" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="132" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="132" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="132" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="132" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="132" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="132" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="144" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="144" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="144" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="144" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="144" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="144" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="144" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="156" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="156" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="156" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="156" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="156" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="156" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="156" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="168" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="168" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="168" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="168" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="168" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="168" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="168" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="180" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="180" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="180" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="180" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="180" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="180" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="180" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="192" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="192" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="192" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="192" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="192" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="192" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="192" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="204" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="204" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="204" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="204" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="204" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="204" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="204" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="216" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="216" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="216" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="216" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="216" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="216" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="216" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="228" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="228" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="228" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="228" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="228" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="228" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="228" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="240" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="240" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="240" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="240" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="240" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="240" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="240" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="252" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="252" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="252" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="252" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="252" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="252" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="252" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="264" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="264" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="264" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="264" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="264" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="264" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="264" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="276" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="276" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="276" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="276" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="276" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="276" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="276" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="288" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="288" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="288" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="288" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="288" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="288" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="288" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="300" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="300" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="300" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="300" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="300" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="300" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="300" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="312" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="312" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="312" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="312" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="312" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="312" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="312" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="324" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="324" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="324" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="324" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="324" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="324" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="324" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="336" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="336" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="336" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="336" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="336" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="336" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="336" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="348" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="348" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="348" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="348" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="348" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="348" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="348" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="360" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="360" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="360" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="360" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="360" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="360" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="360" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="372" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="372" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="372" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="372" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="372" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="372" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="372" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="384" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="384" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="384" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="384" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="384" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="384" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="384" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="396" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="396" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="396" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="396" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="396" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="396" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="396" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="408" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="408" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="408" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="408" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="408" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="408" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="408" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="420" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="420" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="420" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="420" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="420" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="420" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="420" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="432" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="432" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="432" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="432" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="432" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="432" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="432" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="444" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="444" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="444" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="444" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="444" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="444" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="444" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="456" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="456" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="456" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="456" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="456" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="456" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="456" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="468" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="468" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="468" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="468" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="468" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="468" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="468" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="480" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="480" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="480" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="480" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="480" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="480" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="480" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="492" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="492" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="492" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="492" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="492" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="492" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="492" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="504" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="504" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="504" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="504" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="504" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="504" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="504" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="516" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="516" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="516" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="516" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="516" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="516" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="516" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="528" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="528" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="528" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="528" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="528" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="528" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="528" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="540" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="540" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="540" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="540" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="540" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="540" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="540" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="552" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="552" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="552" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="552" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="552" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="552" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="552" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="564" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="564" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="564" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="564" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="564" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.3"/><rect x="564" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="564" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="576" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="576" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="576" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="576" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="576" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="576" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="576" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="588" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="588" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="588" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="588" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="588" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="588" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="588" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="600" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="600" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="600" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="600" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="600" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="600" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="600" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="612" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="612" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="612" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="1"/><rect x="612" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="612" y="48" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="612" y="60" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.75"/><rect x="612" y="72" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="624" y="0" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="624" y="12" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.5"/><rect x="624" y="24" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/><rect x="624" y="36" width="10" height="10" rx="2" fill="currentColor" fill-opacity="0.08"/></svg></div><div class="heatmap-chart-with-year-of-days-data-table"><table><caption>Activity score per month in 2026</caption><thead><tr><th scope="col">Month</th><th scope="col">Score</th></tr></thead><tbody><tr><th scope="row">January</th><td>75</td></tr><tr><th scope="row">February</th><td>50</td></tr><tr><th scope="row">March</th><td>32</td></tr><tr><th scope="row">April</th><td>34</td></tr><tr><th scope="row">May</th><td>51</td></tr><tr><th scope="row">June</th><td>63</td></tr><tr><th scope="row">July</th><td>77</td></tr><tr><th scope="row">August</th><td>56</td></tr><tr><th scope="row">September</th><td>34</td></tr><tr><th scope="row">October</th><td>30</td></tr><tr><th scope="row">November</th><td>48</td></tr><tr><th scope="row">December</th><td>63</td></tr></tbody></table></div></figure> Usage example <HeatmapChartWithYearOfDays label="Activity per day in 2026" year={2026} weekStart={1} aria-describedby="heatmap-chart-with-year-of-days-data">
<svg viewBox="0 0 100 100">…</svg>
</HeatmapChartWithYearOfDays>
<table id="heatmap-chart-with-year-of-days-data">…</table>
Show Svelte source // In your Svelte component:
import HeatmapChartWithYearOfDays from "lily-design-system-svelte-headless/components/HeatmapChartWithYearOfDays/HeatmapChartWithYearOfDays.svelte";
<HeatmapChartWithYearOfDays>
<!-- content -->
</HeatmapChartWithYearOfDays>
Usage
<HeatmapChartWithYearOfDays label="Activity per day in 2026" year={2026} weekStart={1} aria-describedby="heatmap-chart-with-year-of-days-data">
<svg viewBox="0 0 100 100">…</svg>
</HeatmapChartWithYearOfDays>
<table id="heatmap-chart-with-year-of-days-data">…</table>
Props
Prop
Type
Default
Description
class
string
""
Appended to the base class
label
string (required)
—
Accessible name
year
number (required)
—
The calendar year shown; reflected as data-year
weekStart
number (required)
—
First weekday row, 0 = Sunday … 6 = Saturday; reflected as data-week-start. No default: it is locale-dependent
children
slot (required)
—
The consumer-drawn inline <svg>
...restProps
HTML attributes
—
Spread onto the root <figure>, e.g. aria-describedby
Layout contract
The consumer draws the grid; the component names it and carries the two numbers the drawing needs. The grid has seven weekday rows and one column per week, one cell per day of year:
row(d) = (weekday(d) − weekStart + 7) mod 7, with weekday 0 = Sunday … 6 = Saturday, so the first row is the weekday weekStart names.
column(d) = floor((dayOfYear(d) − 1 + row(1 January)) / 7), with dayOfYear(1 January) = 1. The first column holds 1 January; the grid has 53 or 54 columns, and the first and last columns are partly empty.
365 cells, or 366 in a leap year; empty positions draw nothing.
shared/year-of-days-layout.ts implements this once (yearOfDaysCells(year, weekStart) returns { date, dayOfYear, column, row } for every day; columnCount and daysInYear are alongside), in UTC calendar dates so a time zone cannot move a day. It is a pure module a drawing routine copies in, like the other shared/ modules; the component itself does not call it.
weekStart has no default because the first day of the week depends on the reader's locale (Sunday, Monday and Saturday are all in use): the consumer passes it, from Intl.Locale#getWeekInfo() or its own setting. Month and weekday labels, and the legend, come from the consumer through Intl; the component supplies no strings.
Accessible alternative
Colour must not be the only carrier of the value (WCAG 1.4.1), and 365 unnamed cells are not an accessible chart. Supply a dataTable: a real <table> with one row per day, or per week or month when the consumer summarises, listing the date and the value. Do not rely on a <title> inside each cell: the graphic is role="img", so its children are presentational and those titles are never exposed.
Keyboard Interactions
None. The chart is a single image to assistive technology.
A referenced data table follows native table behaviour.
ARIA
role="img" exposes the chart as one image (its children are presentational)
aria-label provides the accessible name
aria-describedby (consumer-supplied) references the description or data table
When to Use
A per-day measure across one year, where the reader looks for streaks, gaps and seasons
When the chart needs the catalog's standard accessible shell and a stable class hook
When a real data table accompanies the drawing as the accessible alternative
When Not to Use
Use HeatmapChart — when the two dimensions are not a calendar year (weekday by hour, for example)
Use LineChart — when the trend matters more than the pattern of individual days
Use DataTable — when readers need exact values and not a pattern
Use CalendarYearTable or CalendarMonthTable — when readers pick or read specific dates, not scan a pattern
Headless
This component decides semantics only: the figure element, the image role and the name. It decides no geometry, scale, colour, legend or motion.
Styles
Target .heatmap-chart-with-year-of-days for the figure and style the supplied <svg> from consumer CSS. No default styles are included.
Testing
year and weekStart reach the figure as data-year and data-week-start
Renders a <figure> with class heatmap-chart-with-year-of-days and a .heatmap-chart-with-year-of-days-graphic child with role="img"
label sets aria-label
aria-describedby and other rest props reach the figure
The consumer svg renders inside the figure
Advice
Fetching the per-day data, and any caching of it, is the consumer's job; the component takes the finished drawing. Pass the grid <svg> as children. Colour alone must never carry the value (WCAG 1.4.1): supply the same numbers as a real <table> and point aria-describedby at it.
Because role="img" makes descendants presentational, never put interactive controls inside the figure; place legends and toggles next to it.
Implementation Notes
Renders <figure class="heatmap-chart-with-year-of-days {class}" data-year data-week-start> containing the children
The consumer supplies the <svg> (and any legend or caption markup)
restProps — including aria-describedby — spread onto the <figure>
No internal state, no drawing, no data handling
Data table alternative (added 2026-10-05)
The graphic is wrapped in <div class="heatmap-chart-with-year-of-days-graphic" role="img" aria-label>; role="img" is not on the <figure> any more. The optional dataTable (a snippet in Svelte, a prop in React, a named slot in Vue, a projected [dataTable] element in Angular, a DataTable render fragment in Blazor, params.dataTable in Nunjucks, a slot="data-table" child in Web Components) renders the accessible table in <div class="heatmap-chart-with-year-of-days-data-table">, a sibling of the graphic and never inside it: role="img" makes its descendants presentational, so a table inside would be invisible to assistive technology. Without a data table the wrapper is not rendered (except Angular, noted above).
Related components
heatmap-chart — the general grid this specialises
calendar-year-table
scatter-chart
data-table
calendar-month-table
line-chart
graphic-block — chart wrapper with title and notes
References
Lily™ and Lily Design System™ are trademarks.
Canonical contract Generated from this component's canonical metadata — the machine-checked source the implementations are held to.
Metadata Component: heatmap-chart-with-year-of-days PascalCase: HeatmapChartWithYearOfDays Description: a heatmap chart of one year of days, one cell per day in week columns and weekday rows Status: experimental — added 2026-10-22; implemented and unit-tested in all nine headless catalogs HTML tag: <figure> CSS class: .heatmap-chart-with-year-of-days Interactive: no ARIA role="img" exposes the chart as a single image aria-label and aria-describedby provide the accessible name and description Keyboard No keyboard interactions on the chart A data table (when rendered) follows native table keyboard behaviour Props class: string (default: "") -- appended to the base class label: string (required) -- accessible name year: number (required) -- the calendar year shown (data-year) weekStart: number (required) -- first weekday row, 0 = Sunday … 6 = Saturday (data-week-start); no default, it is locale-dependent children: slot (required) -- the inline <svg> ...restProps: HTML attributes -- spread onto the root <figure>