Skip to content

Accessibility

D3plus is a collection of tools built on top of the low-level helper functions made available by D3 to help aid in the generation of charts. While D3 itself can be considered accessible out of the box, as it doesn’t actively add any elements to a webpage (see this discussion), D3plus tries its best to make sure that the SVG elements that get added to the page include accessibility features automatically. This page outlines those features.

The @d3plus/color package includes utilities that help ensure text and visual elements remain legible across different color contexts.

The colorContrast function determines whether to use a light or dark text color for any given background. It returns whichever of the two text colors has the higher WCAG 2.x contrast ratio against the background, so the more legible option always wins (for example, bright greens and teals correctly receive dark text). This is applied automatically throughout D3plus when rendering text labels on colored shapes.

import { colorContrast } from "@d3plus/color";
colorContrast("#b22200"); // returns light text color
colorContrast("#f8f9fa"); // returns dark text color

The colorLegible function adjusts a color to ensure it is legible when rendered on a white background. It operates in the HSL color space, capping lightness at 0.45 and reducing saturation when necessary. This is useful for ensuring axis labels, annotations, and legend text meet readability standards.

import { colorLegible } from "@d3plus/color";
colorLegible("#aaddff"); // returns a darkened, legible variant

These utilities support compliance with WCAG 1.4.3 (Contrast Minimum) for text elements within visualizations.

D3plus’s default categorical palette is designed — and automatically validated — for colorblind accessibility. Its eight primary slots sit within a controlled OKLCH lightness band, clear a chroma floor, and stay distinguishable under protanopia, deuteranopia, and tritanopia (Machado-2009 simulation), while maintaining WCAG contrast against the chart surface.

The colorValidate function checks any palette against those same criteria — OKLCH lightness band, chroma floor, colorblind (protan/deutan/tritan ΔE) separation, and WCAG contrast — so you can verify a custom palette is accessible before shipping it. It also supports an ordinal-ramp mode for sequential scales.

import { colorValidate } from "@d3plus/color";
colorValidate(["#4269d0", "#efb118", "#ff725c"]); // pass / warn / fail report

D3plus supports built-in texture and pattern fills as an alternative to color-only data series differentiation, powered by the textures library. Textures can be applied to any shape via the shapeConfig property, providing a non-color visual channel that helps users who are colorblind or viewing charts in grayscale.

Type Description
lines Striped patterns with configurable orientation
circles Circular dot patterns
crosses Cross-shaped patterns
nylon Nylon weave patterns
waves Wave-shaped patterns
woven Woven fabric patterns
squares Square tile patterns
caps Cap-shaped patterns
hexagons Hexagonal tile patterns
grid Shorthand for lines with both vertical and horizontal orientation

Textures are configured through the texture and textureDefault properties inside shapeConfig:

<BarChart config={{
data, groupBy: "id",
shapeConfig: {
texture: "nylon",
textureDefault: {
size: 10,
stroke: "rgba(0, 0, 0, 0.1)",
strokeWidth: 1
}
}
}} />

Textures can also be set as an object with additional options or as a data-driven accessor function:

// Object with configuration
shapeConfig: {
texture: {
texture: "lines",
orientation: "diagonal",
stroke: "darkorange",
strokeWidth: 2,
}
}
// Data-driven texture per group
shapeConfig: {
texture: (d) => d.id === "alpha" ? "circles" : "nylon"
}

All user-facing text in D3plus, including aria-labels and screen reader content, respects the configured locale. The @d3plus/locales package provides translations and number formatting for multiple locales:

UI Translations:

  • Arabic (ar-SA)
  • Spanish (es-ES)
  • Portuguese (pt-BR)
  • Chinese (zh-CN)

Number Formatting:

  • English (en-US, en-GB)
  • Spanish (es-ES, es-MX, es-CL)
  • French (fr-FR)
  • Arabic (ar-SA)
  • Estonian (et-EE)
  • Chinese (zh-CN)

This is relevant to WCAG 3.1.1 (Language of Page) and ensures that accessible text is presented in the appropriate language and number format for the target audience. Locales can be set via the locale configuration method on any visualization.

All shape DOM elements created by D3plus contain a role attribute with the value “presentation”. They also contain an aria-label which describes the data related to the shape. At a minimum, the value will contain the text label of the data point, but additional information (such as rank and/or value) is provided depending on the visualization.

<rect
aria-label="2. United States, 34%."
role="presentation"
width="300"
height="371"
x="-150"
y="-185.5"
fill="#b22200" />

D3plus generates contextual aria-labels tailored to each chart type, so screen reader users receive the most relevant information for the visualization they are interacting with:

Chart Type Label Format Example
Plot (Bar, Line, Area, Stacked Area, Box Whisker, Bump, and the other charts built on Plot) Label with x/y coordinate values "Texas, x: 2020, y: 43218."
Candlestick Label and period with open, high, low, and close "ACME, Jan 2, 2024: Open 101, High 104, Low 99.5, Close 103."
Hexbin A bin’s measure with its x and y ranges, or a contour’s density range "Count: 42, height 170 – 172, weight 68 – 71"
Waterfall Category, step kind, and change "Q2, Increase: +120."
Pyramid Group, category, and value "Male, 20–24: 1.2M."
Pie / Donut Rank, label, and value "1. Agriculture, 340."
Treemap Rank, label, and sum "3. California, 128000."
Network / Rings Label with optional size "Node A, 52."
ArcDiagram Nodes: label with optional size; arcs: source to target, with the link size when sizes vary "Node A, 52.", "Node A to Node B, 4."
Geomap (points) Label with point size "Houston, 2300000."
Geomap (regions) Label with color scale value "Texas, 43218."
Tree Depth level and label "2. Child Node."
Priestley Label with time range "Event A, 1820 - 1860."
Gantt Label, dates, and progress (or a milestone’s date) "Design, Mar 11, 2024 - Mar 22, 2024, Progress 60%."

The svgTitle and svgDesc methods can be set to include additional information about a chart for screen assistive technologies.

<svg aria-labelledby="title desc" aria-hidden="false">
<title id="title">
Bar Chart of Income Over Time
</title>
<desc id="desc">
The income in Texas has been rising steadily over the past 10 years.
</desc>
...
</svg>

All SVG elements created by D3plus contain a role attribute with the value “img”. This ensures that all visualizations are identified as a graphic.

<svg role="img"> ... </svg>

If ariaHidden is set to "false", a visually hidden data table will be rendered inside of the SVG. This makes the data readable by screen assistive technologies, but may overload the DOM in larger websites.

<g role="table">
<text role="row">
<tspan role="columnheader" dy="-1000px">Year</tspan>
<tspan role="columnheader" dy="-1000px">State</tspan>
<tspan role="columnheader" dy="-1000px">Income</tspan>
</text>
<text role="row">
<tspan role="cell" dy="-1000px">2010</tspan>
<tspan role="cell" dy="-1000px">Texas</tspan>
<tspan role="cell" dy="-1000px">43218</tspan>
</text>
...
</g>

Charts honor the viewer’s operating-system “reduce motion” setting. Under the default reducedMotion: "auto", a chart reads the (prefers-reduced-motion: reduce) media query each time it draws; when it matches, the chart skips every animation: entering, updating, and exiting shapes, drill-down morphs, zooming, axis, legend, and timeline changes, and the fades of messages, map tiles, and controls all jump straight to their final state.

Set reducedMotion to true to always draw without motion, or to false to always animate. duration keeps the value you gave it either way, so turning motion back on restores your timing.

new BarChart()
.data(data)
.groupBy("id")
.duration(800)
.reducedMotion("auto") // default: follow the OS setting
.render();

The preference is read when the chart draws, so a change to the OS setting applies at the chart’s next render. Server-side rendering counts as not reduced.

Every chart is one Tab stop, so keyboard users can reach its data without a mouse. Once a chart has focus, these keys move between its data marks:

Key Action
Tab / Shift+Tab Moves focus into the chart (onto its first mark) and on out of it. Focus is never trapped.
← → ↑ ↓ Moves to the nearest mark in that direction. Line and area series are visited point by point, and the legend’s items come after the chart’s marks.
Home / End Jumps to the first or last mark, reading left to right and then top to bottom.
Enter / Space Selects the focused mark, as a click would: it runs click handlers, drills down into nested data, and toggles a legend item (Shift+Enter acts as a shift-click).
Escape Clears the focused mark and its tooltip, leaving focus on the chart.

The focused mark behaves as if the pointer were over it: its tooltip opens, the other marks dim, and a ring outlines it. The chart’s focusable element has role="application", so screen readers pass the arrow keys through to it, and an aria-roledescription of “interactive chart”. It is named by svgTitle (or the chart’s title), described by short instructions, and holds a polite live region that announces each focused mark’s aria-label (see Shape aria-labels). Every label is translated with the chart’s locale.

Keyboard navigation is on by default. keyboardNavConfig styles the focus ring, which defaults to a 2px ring in the color that contrasts with the chart’s background, over a halo of the background color so it stands out against any mark. keyboardNav(false) removes the Tab stop entirely.

new BarChart()
.config({
data,
groupBy: "id",
keyboardNavConfig: {stroke: "#005fcc", strokeWidth: 3, padding: 4},
})
.render();
// No Tab stop, focus ring, or live region.
new BarChart().config({data, groupBy: "id", keyboardNav: false}).render();

Section 508 of the Rehabilitation Act requires federal agencies to ensure their electronic and information technology is accessible. The current Section 508 standards incorporate WCAG 2.0 Level AA by reference, and federal guidance increasingly aligns with WCAG 2.1 Level AA.

The following table summarizes how D3plus addresses the WCAG success criteria most relevant to data visualizations:

# Criterion Status Notes
1.1.1 Non-text Content Supported All shapes include aria-label attributes. Optional svgTitle and svgDesc provide chart-level text alternatives. Inline data table available via ariaHidden: false.
1.3.1 Info and Relationships Supported ARIA roles (img, presentation, table, row, cell, columnheader) convey structure programmatically.
1.3.2 Meaningful Sequence Supported DOM order follows a logical sequence: title, description, legend, axes, then data elements.
1.4.1 Use of Color Supported The default palette is colorblind-safe (validated for protan/deutan/tritan separation). Color is the primary differentiator for data series, and built-in texture and pattern fills (lines, circles, crosses, waves, and more) can be applied via shapeConfig as a non-color visual channel. See Texture Patterns below.
1.4.3 Contrast (Minimum) Supported colorContrast automatically selects light or dark text for labels based on background color. colorLegible ensures text colors meet readability thresholds.
1.4.11 Non-text Contrast Partial The default categorical palette is programmatically validated (colorValidate) for colorblind separation and contrast against the chart surface, and colorValidate is exposed for checking custom palettes. Contrast between arbitrary user-supplied colors is still not automatically enforced.
# Criterion Status Notes
2.1.1 Keyboard Supported keyboardNav (on by default) moves between data marks with the arrow keys, Home, and End, opens their tooltips, and selects them (click handlers, drill-down, legend toggles) with Enter or Space. See Keyboard Navigation.
2.1.2 No Keyboard Trap Supported Visualizations do not trap focus.
2.3.3 Animation from Interactions Supported Charts skip their transitions when the viewer’s OS asks for reduced motion (reducedMotion: "auto", the default), and reducedMotion: true removes them for everyone. See Reduced Motion.
2.4.3 Focus Order Supported Each chart is a single Tab stop in DOM order; inside it, arrow keys move spatially and Home/End follow reading order.
2.4.7 Focus Visible Supported The focused mark gets a ring in the color contrasting with the chart’s background, over a halo of the background color (keyboardNavConfig); the chart itself is outlined while it has focus with no mark selected.
# Criterion Status Notes
3.1.1 Language of Page Supported The locale configuration ensures accessible text is rendered in the appropriate language.
# Criterion Status Notes
4.1.2 Name, Role, Value Supported All shapes expose name (via aria-label), role (via role attribute), and value information to assistive technology. The keyboard-focusable chart has a role, name, and description, and announces the focused mark through a live region.

D3plus is actively working to improve accessibility. The following enhancements are planned:

  • VPAT / Accessibility Conformance Report — Publish a formal ACR using the VPAT 2.5 template to support federal procurement evaluation under Section 508.