Combo chart
Updated
ComboChart draws dithered bars on the left axis and one-cell pixel lines on a right axis whose grid lines up with the bars', the line cut clear of the bars' tone. Like every DitherCharts chart, it fills its container's width, animates in, moves a cursor with the arrow keys, and keeps a data table for screen readers.
Example
Combo
Revenue bars with the conversion rate on a second axis
| month | Revenue | Conversion % |
|---|---|---|
| Jan | 186 | 2.1 |
| Feb | 305 | 3.4 |
| Mar | 237 | 2.8 |
| Apr | 173 | 2.2 |
| May | 209 | 2.9 |
| Jun | 264 | 3.6 |
| Jul | 298 | 4.1 |
| Aug | 251 | 3.5 |
| Sep | 222 | 3 |
| Oct | 276 | 3.8 |
| Nov | 318 | 4.4 |
| Dec | 342 | 4.6 |
import { ComboChart } from "@/components/dithercharts/combo-chart"
import type { ChartConfig } from "@/components/dithercharts/chart-config"
const chartData = [
{ month: "Jan", revenue: 186, conversion: 2.1 },
{ month: "Feb", revenue: 305, conversion: 3.4 },
{ month: "Mar", revenue: 237, conversion: 2.8 },
{ month: "Apr", revenue: 173, conversion: 2.2 },
{ month: "May", revenue: 209, conversion: 2.9 },
{ month: "Jun", revenue: 264, conversion: 3.6 },
{ month: "Jul", revenue: 298, conversion: 4.1 },
{ month: "Aug", revenue: 251, conversion: 3.5 },
{ month: "Sep", revenue: 222, conversion: 3 },
{ month: "Oct", revenue: 276, conversion: 3.8 },
{ month: "Nov", revenue: 318, conversion: 4.4 },
{ month: "Dec", revenue: 342, conversion: 4.6 },
]
const chartConfig = {
revenue: { label: "Revenue" },
conversion: { label: "Conversion %" },
} satisfies ChartConfig
export function ChartCombo() {
return (
<ComboChart
data={chartData}
config={chartConfig}
xKey="month"
lineKeys={["conversion"]}
label="Monthly revenue and conversion"
/>
)
}
Install
Charts install with DitherCharts Pro. See Installation to log in and import the stylesheet.
npx dithercharts add combo-chart
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| datarequired | Type readonly ChartRow[] | Default – | One row per x position, left to right, e.g. { month: "Jan", revenue: 186, conversion: 2.4 }. |
| configrequired | Type ChartConfig | Default – | One entry per data key to plot, in draw and legend order: its label and, optionally, its pattern. |
| xKeyrequired | Type string | Default – | The row key that holds the x label, e.g. "month". |
| lineKeysrequired | Type readonly string[] | Default – | The config keys drawn as lines; every other config key is a bar. Keys not in config are ignored. |
| labelrequired | Type string | Default – | Accessible name, e.g. "Revenue and conversion". Also captions the table twin. |
| dualAxis | Type boolean | Default true | The lines on their own right axis, its grid aligned to the bars' left axis. False puts them on the left axis. |
| legend | Type boolean | Default false | A legend under the chart whose buttons show and hide series. |
| yAxis | Type boolean | Default true | Value labels beside the grid lines, on both axes. |
| stack | Type "none" | "stacked" | Default "none" | The bars side by side, or stacked; the lines never stack. |
| radius | Type number | Default 0 (square, pixel-hard ends) | Corner radius of a bar's ends in CSS pixels, stepped by the dither grid. |
| curve | Type "monotone" | "linear" | "step" | Default "monotone" | How the lines run between points. |
| dots | Type "square" | "ring" | Default none | A dot on every line point: a solid square, or a hollow ring that knocks the line out. |
| tooltip | Type TooltipOptions | Default – | The tooltip's indicator and label, and the x position it opens on at rest. |
| style | Type StyleId | Default "bayer4" | Dither style. |
| animation | Type "develop" | "none" | Default "develop" | Entrance animation; reduced motion always shows the final frame. |
| height | Type number | Default 300 | Height in CSS pixels; the width fills the container. |
| cell | Type number | Default 3 | Dither cell size in CSS pixels; a line is one cell wide. |
| className | Type string | Default – | Classes on the chart's outer figure. |
Styles
The dither styles style takes:
"bayer2""bayer4""bayer8""blue-noise""halftone""crosshatch""pixel""stipple""engraved""mezzotint""woodcut""floyd-steinberg""atkinson""riemersma"
Keyboard and accessibility
The chart is one Tab stop. Focusing it from the keyboard puts the cursor on the first column, or where the keys last left it; moving focus away clears it. The keys stop at the ends.
| Key | Action |
|---|---|
| Left arrow Right arrow | Previous / next column |
| Home End | First / last column |
| Up arrow Down arrow | Previous / next series (2+ series) |
| Escape | Dismiss the cursor |
Screen readers
- The chart's label names it, says how many columns it has and lists these keys.
- Each key press is announced in a polite live region. Moving the pointer is silent.
- The
tablebutton under the chart shows its data as a table. Screen readers can reach the table even while it's hidden; clicking a row moves the cursor there and announces it. - With
legend, each entry is a toggle button. The last one showing can't be hidden, but its button stays focusable.
On a touch screen, a tap pins the cursor and a tap outside the chart dismisses it.

