AdminKitDocs
Charts

Next.js Heatmap Chart

A Next.js heatmap chart for the App Router: an ApexCharts client component in AdminKit PRO that shades a grid of cells by value, with theme color ranges.

Pro

This component is only available in AdminKit PRO. Learn more.

A heatmap uses color the way a bar chart uses height. Each cell of the grid is shaded by its value, so dense and quiet areas show up as dark and light patches. In AdminKit for Next.js, the ApexChart client component draws it with ApexCharts. The component is described in Chart setup.

The chart draws in the browser only, while your page is a server component that renders on the server. A server component cannot pass the options function to a client component. Write the chart as a client component file, one that starts with "use client", and render that from the page. The server render, and the static HTML of the export, contain a skeleton of the chart's size.

Example

src/components/metrics-heatmap.tsx
"use client";

import { ApexChart } from "@/components/plugins/apexcharts";

const generateData = (count: number, yrange: { min: number; max: number }) =>
  Array.from({ length: count }, (_, i) => ({
    x: (i + 1).toString(),
    y: Math.floor(Math.random() * (yrange.max - yrange.min + 1)) + yrange.min,
  }));

// Nine rows of 20 random values, generated once when the module loads
const series = Array.from({ length: 9 }, (_, i) => ({
  name: `Metric${i + 1}`,
  data: generateData(20, { min: 0, max: 90 }),
}));

export function MetricsHeatmap() {
  return (
    <div className="position-relative" style={{ minHeight: 365 }}>
      <ApexChart
        options={() => ({
          chart: { height: 350, type: "heatmap" },
          dataLabels: { enabled: false },
          colors: ["#008FFB"],
          series,
          xaxis: { type: "category" },
        })}
      />
    </div>
  );
}
src/app/(dashboard)/metrics/page.tsx
import { MetricsHeatmap } from "@/components/metrics-heatmap";
import { pageMetadata } from "@/lib/site";

export const metadata = pageMetadata("/metrics");

export default function MetricsPage() {
  return (
    <div className="card">
      <div className="card-body">
        <MetricsHeatmap />
      </div>
    </div>
  );
}

pageMetadata() reads the route's title and description from src/data/pages.json, so add /metrics there.

The random values are generated at module level. The wrapper calls options again when the color mode changes, so values generated inside it would reshuffle the cells.

The server and the browser each run Math.random() and get different numbers. Only the browser draws the chart, though, so this causes no hydration mismatch: the browser's first render still matches the server HTML.

Props

PropTypeDefaultDescription
options(theme: Theme) => ApexOptionsThe ApexCharts options, with series and chart.type. Called again with the new colors when the color mode changes

Colors

ApexCharts shades each row in one color, from light (low) to full (high). colors: ["#008FFB"] is the fixed blue of the HTML version. colors: [theme.primary] follows the theme instead.

In dark mode, the wrapper switches the tooltips only. It leaves ApexCharts' theme.mode alone, as that shades heatmaps towards black.

Sometimes a few named bands say more than a gradient. To map value bands to theme colors, use plotOptions.heatmap.colorScale.ranges. The legend shows each band's name:

options={(theme) => ({
  chart: { height: 350, type: "heatmap" },
  dataLabels: { enabled: false },
  series,
  plotOptions: {
    heatmap: {
      colorScale: {
        ranges: [
          { from: 0, to: 30, color: theme.success, name: "Low" },
          { from: 31, to: 60, color: theme.warning, name: "Medium" },
          { from: 61, to: 90, color: theme.danger, name: "High" },
        ],
      },
    },
  },
})}

Accessibility

  • Shades are hard to read as numbers. dataLabels: { enabled: true } prints each value in its cell, if the cells are large enough at your width.
  • Color ranges get a legend with their names, which gives the colors a key.
  • Cell values show in the tooltip on hover only.
  • Name the chart with role="figure" and aria-label on ApexChart: other props go to its <div>.

Last updated on

On this page