Scatter Chart
import { ScatterChart } from '@absoluteui/components/scatter-chart';import '@absoluteui/components/scatter-chart/style.css';Using Angular? See Scatter Chart for Angular.
What it does
Section titled “What it does”An accessible SVG scatter plot of one or more series of (x, y) points on linear axes; a size on points makes it a bubble chart (bubble area proportional to size). It provides:
- keyboard-reachable points (one tab stop) ordered by x within each series, Up/Down between series, with a tooltip on focus and hover;
- a legend of toggle buttons that show and hide series;
- an optional crosshair (vertical and horizontal lines) through the hovered or focused point;
- optional zoom and pan along x (
zoom: 'x') or both axes (zoom: 'xy'); - a generated accessible summary (per-series point counts and x/y ranges) and a data table fallback with the exact values;
- series that differ by color and marker shape, never by color alone (WCAG 1.4.1).
When to use
Section titled “When to use”- Relationships or correlation between two numeric variables.
- Clusters and outliers across a few groups (up to about 8 series).
- A third numeric dimension as bubble size (sizes set on points).
When not to use
Section titled “When not to use”- Trends over an ordered x shared by all series: use Line Chart.
- Comparing categories: use Bar Chart or Combo Chart.
- Distribution of one variable: use Histogram (or Box Plot).
- Very large point clouds (tens of thousands of points): not a target of this component.
Examples
Section titled “Examples”Two groups with named axes, crosshair, and xy zoom
Section titled “Two groups with named axes, crosshair, and xy zoom”import { ScatterChart, type ScatterChartZoomDetail } from '@absoluteui/components/scatter-chart';
const host = document.createElement('div');document.body.append(host);const chart = ScatterChart.create(host, { label: 'Height and weight', series: [ { id: 'a', label: 'Group A', points: [{ x: 160, y: 55 }, { x: 175, y: 72 }, { x: 182, y: 80 }] }, { id: 'b', label: 'Group B', points: [{ x: 150, y: 48 }, { x: 170, y: 65 }] }, ], xAxis: { label: 'Height (cm)' }, yAxis: { label: 'Weight (kg)' }, crosshair: true, zoom: 'xy',});host.addEventListener('aui-zoom', (event) => { const { x, y } = (event as CustomEvent<ScatterChartZoomDetail>).detail; host.dataset.zoomed = String(x !== null || y !== null);});chart.update({ zoomRange: { from: 155, to: 180 } });Bubble chart with labelled points and a size dimension
Section titled “Bubble chart with labelled points and a size dimension”import { ScatterChart } from '@absoluteui/components/scatter-chart';
const host = document.querySelector<HTMLElement>('#markets');if (host) { ScatterChart.create(host, { label: 'Markets', series: [{ id: 'm', label: 'Markets', color: 4, points: [ { x: 2.1, y: 18, size: 120, label: 'North' }, { x: 3.4, y: 11, size: 60, label: 'South' }, { x: 1.2, y: 25, size: 300, label: 'West' }, ], }], xAxis: { label: 'Growth (%)', includeZero: true }, yAxis: { label: 'Margin (%)' }, sizeLabel: 'Revenue (M)', sizeRange: [6, 30], dataTable: 'visible', });}import { ScatterChart } from '@absoluteui/components/scatter-chart';import '@absoluteui/components/scatter-chart/style.css';
const host = document.querySelector<HTMLElement>('#markets');if (host) { ScatterChart.create(host, { label: 'Markets', series: [{ id: 'm', label: 'Markets', points: [{ x: 2.1, y: 18, size: 120, label: 'North' }, { x: 3.4, y: 11, size: 60, label: 'South' }] }], xAxis: { label: 'Growth (%)' }, yAxis: { label: 'Margin (%)' }, sizeLabel: 'Revenue (M)', zoom: 'xy', });}More usage
Section titled “More usage”import { ScatterChart } from '@absoluteui/components/scatter-chart';
const host = document.createElement('div');document.body.append(host);ScatterChart.create(host, { label: 'Height and weight', series: [{ id: 'a', label: 'Group A', points: [{ x: 160, y: 55 }, { x: 175, y: 72 }] }], xAxis: { label: 'Height (cm)' }, yAxis: { label: 'Weight (kg)' },});Export: @absoluteui/components/chart-export (chartToSvg, chartToPng, downloadChart) exports any chart instance to SVG or PNG.
Anatomy
Section titled “Anatomy”<div class="aui-chart aui-scatter-chart [aui-scatter-chart--bubble] [aui-chart--patterns] [aui-chart--zoomable] [aui-chart--zoomed]"> <div class="aui-chart__header"> <div class="aui-chart__title" id="T">title</div> <p class="aui-chart__description" id="D">description</p> <div class="aui-chart__toolbar"> (zoom enabled; hidden otherwise) <div class="aui-chart__zoom" role="group" aria-label="Zoom"> <button class="aui-chart__tool" aria-label="Zoom in"/> <button class="aui-chart__tool" aria-label="Zoom out" aria-disabled="true"/> <button class="aui-chart__tool" aria-label="Reset zoom" aria-disabled="true"/> </div> </div> </div> <ul class="aui-chart__legend" aria-label="Legend"> <li class="aui-chart__legend-entry"><button class="aui-chart__legend-item" aria-pressed="true"><svg class="aui-chart__swatch" aria-hidden="true"/>Group A</button></li> </ul> <div class="aui-chart__body"> (height: --aui-chart-height) <svg class="aui-chart__svg" role="group" aria-roledescription="scatter chart" aria-labelledby="T" aria-describedby="D S"> <g class="aui-chart__crosshair" aria-hidden="true"><line class="aui-chart__crosshair-line"/><line class="aui-chart__crosshair-line"/></g> (crosshair: true) <g class="aui-chart__grid" aria-hidden="true"/> <g class="aui-chart__axis …" aria-hidden="true"/> <g class="aui-scatter-chart__points"> (clipped to the plot while zoomed) <g class="aui-scatter-chart__series aui-chart__series--c1"> <path class="aui-chart__mark aui-scatter-chart__point [aui-scatter-chart__bubble]" role="img" aria-label="Group A: Height (cm) 160, Weight (kg) 55" tabindex="0"/>... </g> </g> </svg> <div class="aui-chart__empty" hidden/> <div class="aui-chart__tooltip" aria-hidden="true" hidden/> </div> <p class="aui-chart__summary" id="S" hidden>generated summary</p> <div class="aui-chart__data"><button class="aui-chart__table-toggle" aria-expanded="false" aria-controls="R">Show data table</button><div class="aui-chart__table-scroll" id="R" role="region"><table class="aui-chart__table">...</table></div></div></div>API reference
Section titled “API reference”Factory
Section titled “Factory”ScatterChart.create(host: HTMLElement, options: ScatterChartOptions): ScatterChartGlobal configuration key: scatterChart (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Chart title: visible text and the accessible name of the plot (aria-labelledby). Required. | |
hideLabel |
boolean |
false |
Visually hide the title; it stays the accessible name. |
description |
string |
Visible description below the title, also referenced by aria-describedby (text only). | |
summary |
string |
Replaces the generated accessible summary (aria-describedby). | |
valueFormat |
Intl.NumberFormatOptions |
Number format for values in tooltips, labels, the data table, the summary, and axis ticks (ticks use fixed fraction digits). | |
formatValue |
(value: number) => string |
Custom value text; overrides valueFormat everywhere except axis ticks. | |
hiddenSeries |
readonly string[] |
Ids of series hidden initially; update() replaces the hidden set. | |
series |
readonly ScatterChartSeries[] |
Series: { id, label, points: { x: number; y: number; size?: number; label?: string }[], color?: 1-8 }. Ids are unique and non-empty. Points with a non-finite x or y are skipped. Any point with a size makes the chart a bubble chart. Required. | |
xAxis |
{ label?: string; min?: number; max?: number; tickCount?: number; includeZero?: boolean } |
X axis title, fixed domain (min < max), approximate tick count (2-20), and zero inclusion (default false). The title also names x in point labels, tooltips, and the table (default “X axis”). | |
yAxis |
{ label?: string; min?: number; max?: number; tickCount?: number; includeZero?: boolean } |
Y axis title, fixed domain, tick count, and zero inclusion (default false). The title also names y (default “Y axis”). | |
sizeLabel |
string |
"Size" |
Name of the size dimension in bubble labels, tooltips, and the table. |
sizeRange |
readonly [number, number] |
[4,24] |
Bubble radius in CSS px for the smallest and largest size (each 1-100, min <= max). Area is proportional to size. |
xFormat |
Intl.NumberFormatOptions |
Number format of x values (ticks, labels, tooltips, table, summary). Default: valueFormat. | |
zoom |
'none' | 'x' | 'xy' |
"none" |
Zoom and pan along x or both axes: a Zoom toolbar (Zoom in, Zoom out, Reset zoom), +/= and - and 0 keys on a focused point, Ctrl/Cmd + wheel, drag to pan a zoomed chart, Shift + drag to select a range. Turning it off resets the window. |
zoomRange |
ChartZoomRange | null |
Visible x window { from, to } in data units; null shows everything. Clamped to the data (minimum span 1/50 of the extent). Applied without an aui-zoom event; use with zoom enabled. | |
zoomRangeY |
ChartZoomRange | null |
Visible y window with zoom: “xy” (ignored otherwise); null shows everything. | |
legend |
'auto' | 'show' | 'hide' |
"auto" |
auto: legend when there is more than one series. Entries are toggle buttons. Globally configurable. |
dataTable |
'toggle' | 'visible' | 'hidden' | 'none' |
"toggle" |
Data table fallback with the exact data: behind a Show data table button (built on first open), always visible, visually hidden (screen readers only), or none. Globally configurable. |
tooltip |
boolean |
true |
Tooltip on pointer hover and keyboard focus. Globally configurable. |
patterns |
boolean |
false |
Texture fills (and dash patterns for lines) so marks never differ by color alone (always on in forced colors). Globally configurable. |
height |
number |
300 |
Plot height in CSS px (integer 120-2000); the width follows the container. Globally configurable. |
crosshair |
boolean |
false |
Crosshair lines (vertical and horizontal, aria-hidden) through the hovered or focused point. Globally configurable. |
locale |
string |
"en-US" |
Number and message locale. Globally configurable. Inherited from common configuration. |
direction |
'ltr' | 'rtl' |
"ltr" |
rtl mirrors the x axis, puts the value axis on the right, and swaps ArrowLeft/ArrowRight. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
The host element. |
element |
SVGSVGElement |
The plot (svg role=“group”), named by the title and described by the summary. |
summary |
string |
The generated (or custom) accessible summary. |
hiddenSeries |
string[] |
Ids of hidden series, in data order. |
zoomRange |
ChartZoomRange | null |
Current visible x window, or null. |
zoomRangeY |
ChartZoomRange | null |
Current visible y window (zoom: “xy”), or null. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
update(options: Partial<ScatterChartOptions>): void |
Merge, validate, and re-render. Invalid options throw and keep the previous state. Keyboard focus stays on the same mark when it still exists. |
setSeriesVisible(id: string, visible: boolean): void |
Show or hide a series programmatically; emits no event. |
destroy(): void |
Remove rendering, host classes, listeners, the resize observer, and the configuration subscription. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-series-toggle |
{ id: string; visible: boolean; hidden: string[] } |
Yes | No | The user toggled a legend entry (pointer or keyboard). Not emitted for update() or setSeriesVisible(). |
aui-zoom |
ScatterChartZoomDetail = ChartZoomDetail: { x: ChartZoomRange | null; y: ChartZoomRange | null; reason: 'button' | 'keyboard' | 'wheel' | 'pan' | 'select' | 'reset' } |
Yes | No | The user changed the visible window (toolbar, keys, Ctrl/Cmd + wheel, drag pan, Shift + drag selection). x and y are null when that axis shows everything (y is always null with zoom: “x”). Not emitted for the zoom range options or when the window does not change. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-chart |
Host (shared chart chrome). |
aui-scatter-chart |
Host modifier for this chart type. |
aui-chart--patterns |
patterns option on: textures (and dash patterns) shown. |
aui-chart__header / __title / __title--hidden / __description |
Title and description. |
aui-chart__legend / __legend-entry / __legend-item / __legend-item--hidden / __legend-label |
Legend list and its entries. |
aui-chart__swatch |
aria-hidden legend and tooltip key (marker, dash, texture). |
aui-chart__body / __svg / __layer |
Plot container (height from –aui-chart-height), SVG, and drawing layer. |
aui-chart__grid / __gridline / __zero-line / __axis / __axis-line / __tick-label / __axis-title |
Axes (aria-hidden). |
aui-chart__series--c1 ... --c8 |
Palette slot classes; set –aui-chart-color from color-chart-<n>. |
aui-chart__mark / __mark--active / __mark--hover |
Focusable data mark and its states. |
aui-chart__tooltip / __tooltip-title / __tooltip-rows / __tooltip-row / __tooltip-label / __tooltip-value |
Tooltip (aria-hidden; the focused mark carries the same text). |
aui-chart__empty |
Empty state text (No data, All series are hidden). |
aui-chart__summary |
Hidden summary referenced by aria-describedby. |
aui-chart__data / __data--hidden / __table-toggle / __table-scroll / __table / __cell--numeric |
Data table fallback. |
aui-chart--zoomable / aui-chart--zoomed |
Host modifiers: zoom enabled (touch-action pan-y on the body); a window is applied (grab cursor). |
aui-chart__toolbar / __zoom / __tool |
Header toolbar (hidden while empty), the Zoom button group, and its icon buttons (aria-disabled when unavailable). |
aui-chart__crosshair / __crosshair-line |
aria-hidden crosshair lines drawn under the marks (crosshair option). |
aui-chart__brush |
Range-selection rectangle while Shift + dragging. |
aui-scatter-chart--bubble |
Host modifier while any point has a size (bubble chart). |
aui-scatter-chart__points / __series / __point / __bubble / __cursor |
Points layer (clipped while zoomed), series group, point marker, translucent bubble, and the proxy mark of dense data. |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-chart-1 | --aui-color-chart-2 | --aui-color-chart-3 | --aui-color-chart-4 | --aui-color-chart-5 | --aui-color-chart-6 | --aui-color-chart-7 | --aui-color-chart-8 | --aui-color-chart-axis | --aui-color-chart-grid | --aui-color-focus-ring | --aui-color-hover | --aui-color-link | --aui-color-surface | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-muted | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-size-xs | --aui-font-weight-medium | --aui-font-weight-regular | --aui-font-weight-semibold | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-shadow-md | --aui-space-1 | --aui-space-2 | --aui-space-3 | --aui-tooltip-max-width | --aui-touch-target-min
TypeScript definitions
Section titled “TypeScript definitions”interface ScatterChartPoint { x: number; y: number; size?: number; label?: string }interface ScatterChartSeries { id: string; label: string; points: readonly ScatterChartPoint[]; color?: ChartColor }interface ScatterChartAxis { readonly label?: string; readonly min?: number; readonly max?: number; readonly tickCount?: number; readonly includeZero?: boolean }interface ScatterChartConfig { legend: ChartLegendMode; dataTable: ChartTableMode; tooltip: boolean; patterns: boolean; height: number; crosshair: boolean }type ChartZoomMode = 'none' | 'x' | 'xy';interface ChartZoomRange { readonly from: number; readonly to: number }interface ScatterChartOptions extends ChartCommonOptions, Partial<ScatterChartConfig> { series: readonly ScatterChartSeries[]; xAxis?: ScatterChartAxis; yAxis?: ScatterChartAxis; sizeLabel?: string; sizeRange?: readonly [number, number]; xFormat?: Intl.NumberFormatOptions; zoom?: ChartZoomMode; zoomRange?: ChartZoomRange | null; zoomRangeY?: ChartZoomRange | null;}type ScatterChartSeriesToggleDetail = { id: string; visible: boolean; hidden: string[] };type ScatterChartZoomDetail = { x: ChartZoomRange | null; y: ChartZoomRange | null; reason: 'button' | 'keyboard' | 'wheel' | 'pan' | 'select' | 'reset' };Accessibility
Section titled “Accessibility”Pattern: SVG chart as a named, described group (role=“group” with aria-roledescription) of role=“img” data marks with roving focus; data table fallback (native table). Follows the WAI Complex Images tutorial (short name plus long description) and the roving tabindex technique of WAI-ARIA APG.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| ArrowLeft / ArrowRight | Point focused | Previous / next point of the same series in x order (then y); mirrored in RTL. |
| ArrowUp / ArrowDown | Point focused, more than one visible series | Point at the nearest x-order position in the previous / next visible series. With one series: previous / next point. |
| Home / End | Point focused | First / last point of the series (x order). |
| PageUp / PageDown | Point focused | Ten points back / forward. |
| Escape | Tooltip visible | Hides the tooltip without moving focus (WCAG 1.4.13); it returns on the next move. |
| Tab / Shift+Tab | Any | Zoom buttons (zoom enabled), legend buttons, then one tab stop for the plot (the active point), then the Show data table button and table region. |
| Enter / Space | Legend button | Shows or hides the series (native button). |
| + / = | Mark focused, zoom enabled | Zoom in around the focused mark. |
| - | Mark focused, zoom enabled | Zoom out around the focused mark. |
| 0 | Mark focused, zoom enabled | Reset zoom (show all data). |
| Enter / Space | Zoom button | Zoom in, zoom out, or reset (native button; ignored while aria-disabled). |
| Element | Role |
|---|---|
| svg.aui-chart__svg | group with aria-roledescription (localized chart type), named by the title |
| data marks | img with an aria-label: point name or series, x and y with their axis names (and size for bubbles) |
| legend | list (ul) named “Legend”; entries are toggle buttons (aria-pressed) |
| zoom toolbar (zoom enabled) | group named “Zoom” of native buttons “Zoom in”, “Zoom out”, “Reset zoom” |
| axes, decorative dense-point paths, tooltip, crosshair, selection brush | aria-hidden (decorative duplicates of the accessible data) |
| data table | table (native) with caption, column headers, and row headers; wide tables scroll in a focusable region |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-labelledby |
svg | id of the visible (or visually hidden) title |
aria-describedby |
svg | description id (when provided) and the generated summary id |
aria-roledescription |
svg | Localized “scatter chart” or “bubble chart” |
aria-label |
each mark | Localized “{name}: {xAxis} {x}, {yAxis} {y}” (bubbles add “, {sizeAxis} {size}”); name is “{label}, {series}” for labelled points, else the series label. Example: “Group A: Height (cm) 160, Weight (kg) 55” |
tabindex |
active mark | 0 on exactly one mark (roving); other marks have none |
aria-pressed |
legend button | true while the series is visible |
aria-expanded / aria-controls |
Show data table button | Table open state and the table region id |
aria-disabled |
zoom buttons | true while the action is unavailable (Zoom in at the minimum span, Zoom out and Reset zoom when not zoomed); the button stays focusable |
Roving focus: one point is in the tab sequence and remembers the last visited point across re-renders (resize, update, zoom) while it stays in view. Points outside the zoom window are not focusable. Toggling a legend entry keeps focus on its button; toggling the table keeps focus on the table button; zoom buttons stay focusable while aria-disabled.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- The generated summary names the chart type, series and point counts, and per series its point count and x and y ranges, plus hidden series.
- Meaning never depends on color alone: each series has its own marker shape, repeated in the legend key.
- Forced colors: marks use CanvasText (bubbles and outlines Canvas/CanvasText) and keep shapes and textures; focus uses Highlight.
- No animation: nothing moves on render; hover and focus emphasis transitions are removed under prefers-reduced-motion and animation: none.
- Above 600 visible points, points are virtual: two proxy marks alternate focus so every move is announced. Browse-mode users read the exact values from the data table.
- Zoom changes are announced politely (“Showing {from} to {to}.” or “Showing all data.”) and emitted as aui-zoom. Pointer gestures (Ctrl/Cmd + wheel, drag pan, Shift + drag selection) have keyboard and toolbar equivalents.
- The crosshair (crosshair option) is aria-hidden and follows both hover and keyboard focus; it hides when focus and the pointer leave.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver, TalkBack) is pending.
- aria-roledescription support varies; screen readers without it announce “group”.
Behavior
Section titled “Behavior”States
Section titled “States”default, bubble (any point has a size), empty (“No data”), all series hidden (“All series are hidden”), series hidden, point focused (tooltip), hovered (nearest point within 12 px), crosshair shown, zoomed, panning or selecting (pointer drag), table open, dense (virtual points above 600 visible points).
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| any | legend button (click, Enter, Space) | series hidden or shown; aui-series-toggle emitted; domains rescale to visible series |
| plot not focused | Tab | active point focused, tooltip (and crosshair) shown |
| point focused | arrow keys, Home, End, PageUp, PageDown | another point focused |
| tooltip visible | Escape | tooltip hidden, focus unchanged |
| not zoomed | Zoom in, +/=, Ctrl/Cmd + wheel up, Shift + drag |
zoomed; “Showing {from} to {to}.” announced; aui-zoom emitted |
| zoomed | Zoom out, -, drag |
window widened or moved; announced; aui-zoom emitted |
| zoomed | Reset zoom, 0 |
all data shown (“Showing all data.”); aui-zoom with x: null, y: null |
| table closed | Show data table | table built and shown |
| any | container resize | re-render at the new width; focus kept on the same point |
Accessibility notes
Section titled “Accessibility notes”- The summary names the type, series and point counts, and per series its point count and x and y ranges, plus hidden series.
- With more than 600 visible points, points are virtual: two proxy marks alternate focus so each move is announced; browse-mode users read values from the data table.
- Series differ by marker shape (repeated in the legend key); forced colors keep shapes and use
CanvasText/Canvas, focus usesHighlight. - Zoom changes are announced politely; every pointer gesture has a keyboard and toolbar equivalent (WCAG 2.1.1, 2.5.1). The crosshair follows hover and keyboard focus and is
aria-hidden. - The tooltip meets WCAG 1.4.13: shown on focus and hover, dismissible with Escape, hoverable, persistent. Nothing animates.
- Manual screen-reader verification is pending.
Responsive behavior
Section titled “Responsive behavior”The width follows the container (ResizeObserver); the height is height. Tick counts follow the plot size; the scales are inset by the largest mark radius so marks never cover the axes. Reflows at 320 CSS px; wide data tables scroll in a focusable region.
Right-to-left
Section titled “Right-to-left”direction: 'rtl' mirrors the x axis (smallest x at the right), puts the y axis on the right, and swaps ArrowLeft/ArrowRight; drag panning follows the mirrored axis. The legend, tooltip, and table follow the document direction.
Theming
Section titled “Theming”Series colors come from color-chart-1..8 by palette slot (series position, or color). Bubbles are translucent with a solid outline in the series color so overlapping bubbles stay visible. Gridlines use color-chart-grid, axes and the crosshair color-chart-axis.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { scatterChart: { crosshair: true, dataTable: 'hidden', height: 360 } } });Changes apply to existing instances immediately.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic. zoom, zoomRange, and zoomRangeY are instance-only.
Timezones
Section titled “Timezones”Not applicable: numeric axes only; no dates are formatted.
No icons option. Markers are drawn shapes. The zoom buttons render the icons plus, minus, and refresh through @absoluteui/icons; a global icon provider or registry entry for those names replaces them in every component that uses them.
Security
Section titled “Security”All text uses textContent; SVG is built with createElementNS. Colors are classes; the plot height and tooltip position are written through the CSSOM. No innerHTML, style attributes, or inline handlers: compatible with style-src 'self' and require-trusted-types-for 'script'.
Data handling
Section titled “Data handling”Renders the given data only; no persistence, network access, or telemetry. Validation errors name the option, never its value.
Performance
Section titled “Performance”Budget: ScatterChart.create with 2,000 points under 60 ms in headless Chromium, including the first render (e2e performance test, tests/e2e/perf-r3.spec.ts). Above 600 visible points, points are virtual (two proxy marks plus one decorative path per series); hover uses a spatial hash; the data table is built only when opened in toggle mode.
Supported data scale
Section titled “Supported data scale”Tested with 2,000 points. DOM size is independent of the point count above 600 visible points.
Edge cases
Section titled “Edge cases”- No series, or no points at all: “No data”. Visible series without any finite point: “No data”.
- Every series hidden: “All series are hidden”.
- All sizes equal: every bubble uses the middle of
sizeRange. - Points without
sizein a bubble chart are drawn as regular markers. - The data table lists every series (including hidden ones); unlabelled points are named “Point {n}”.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
SCATTER_CHART_OPTIONS |
configuration | Missing label; series ids not unique or empty; points without numeric x/y; negative size; invalid axis options; sizeRange outside 1-100 or reversed; invalid zoom or zoom ranges. |
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION |
configuration | Invalid or unknown configuration (for example height outside 120-2000). |
A failed construction leaves the host untouched; a failed update() keeps the previous state.
Known limitations
Section titled “Known limitations”- Linear axes only.
- Keyboard order within a series is by x (then y), not data order.
- Axis label widths are estimated (about 0.6 em per character).
- Manual screen-reader verification is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- Logarithmic or time axes.
- Trend lines, regression, density contours.
- Lasso selection; linked brushing across charts.
- HTML in labels or tooltips.