# `PhiaUi.Components.HeatmapCalendar`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/calendar/heatmap_calendar.ex#L1)

Heatmap calendar grid component for PhiaUI.

Renders a GitHub-style contribution heatmap — a 2-D grid where each cell's
colour intensity represents the magnitude of a metric at that position.

CSS-only — no JS hook required. Fully server-rendered.

## When to use

Common use cases for heatmap grids:

- **GitHub contribution graph** — activity over 52 weeks × 7 days
- **Site traffic heatmap** — hour-of-day vs. day-of-week (24 × 7)
- **Server load matrix** — CPU/memory over time buckets
- **Sales frequency grid** — products vs. months
- **Error rate map** — services vs. deployment environments

## Intensity levels

Values are bucketed into 5 levels (0–4) relative to `max_value`.
Add the following CSS to your stylesheet or `priv/static/theme.css` to apply
colours (these use the primary token so they respect the active theme):

    .heatmap-0 { background-color: oklch(var(--muted)); }
    .heatmap-1 { background-color: oklch(var(--primary) / 0.2); }
    .heatmap-2 { background-color: oklch(var(--primary) / 0.4); }
    .heatmap-3 { background-color: oklch(var(--primary) / 0.65); }
    .heatmap-4 { background-color: oklch(var(--primary) / 0.9); }

## Data format

Pass a flat list of `%{col: integer, row: integer, value: integer}` maps.
Positions not present in `data` are treated as value `0` (level 0, empty).

## Example — GitHub-style contribution heatmap

    # Build 52 weeks × 7 days of contribution data from the database:
    data =
      Contributions.last_year(user_id)
      |> Enum.map(fn c -> %{col: c.week, row: c.day_of_week, value: c.count} end)

    <.heatmap_calendar
      data={data}
      rows={7}
      cols={52}
      row_labels={~w[Sun Mon Tue Wed Thu Fri Sat]}
      max_value={10}
      show_legend={true}
    />

## Example — hourly traffic heatmap (24 hours × 7 days)

    <.heatmap_calendar
      data={@traffic_data}
      rows={7}
      cols={24}
      row_labels={~w[Mon Tue Wed Thu Fri Sat Sun]}
      col_labels={~w[0h 3h 6h 9h 12h 15h 18h 21h]}
      max_value={@peak_traffic}
      show_legend={true}
    />

## Accessibility

The grid uses `role="grid"` on each row container. Each cell uses
`role="gridcell"` and an `aria-label` describing its position and raw value
so keyboard users and screen readers can navigate the matrix.

# `heatmap_calendar`

Renders a heatmap calendar grid.

Builds a `{col, row} => value` lookup map from the `data` list at render time,
then iterates `rows × cols` to produce a WAI-ARIA grid. Each cell receives
a `heatmap-{0..4}` CSS class derived from the bucketed intensity.

The outer `overflow-x-auto` wrapper allows wide grids (e.g. 52 columns) to
scroll horizontally on narrow screens without breaking the page layout.

## Attributes

* `data` (`:list`) - List of `%{col: integer, row: integer, value: integer}` maps.
  `col` and `row` are 0-based indices. Positions absent from the list are
  treated as `value: 0` (rendered at intensity level 0).

  Defaults to `[]`.
* `rows` (`:integer`) (required) - Number of rows in the grid (e.g. `7` for days of the week).
* `cols` (`:integer`) (required) - Number of columns in the grid (e.g. `52` for weeks in a year, `24` for hours).
* `max_value` (`:integer`) - Maximum expected value used to normalise raw values into intensity buckets 0–4.
  Values at or above `max_value` are clamped to level 4.
  Set this to your 95th-percentile value to avoid a single outlier washing out the rest.

  Defaults to `10`.
* `col_labels` (`:list`) - Optional list of column header strings. For readability, pass a subset —
  not every column needs a label. Length need not match `cols`.
  Example: `~w[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec]` for monthly buckets.

  Defaults to `nil`.
* `row_labels` (`:list`) - Optional list of row label strings. Length should match `rows`.
  Example: `~w[Sun Mon Tue Wed Thu Fri Sat]` for day-of-week rows.

  Defaults to `nil`.
* `show_legend` (`:boolean`) - When `true`, renders a small "Less → More" intensity legend below the grid.
  Recommended when the colour scale is not self-evident from context.

  Defaults to `false`.
* `class` (`:string`) - Additional CSS classes for the root wrapper. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the root div.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
