Skip to content

Accessibility

The canvas is aria-hidden. Beside it, the explorer renders an outline: the current scene as real links (each item’s href) and buttons (a hollow aggregate), with its badges (marks). It is visually hidden, but read aloud and reachable by keyboard. The demo shows it, so you can see what is announced as you move.

Running the code below: accessibility.tsx
accessibility.tsx
import { useState } from "react";
import { createSceneSource, DataExplorer } from "@data-xplorer/core";
// The canvas is hidden from assistive technology; the outline beside it is not. It lists the
// scene as real links (each item's `href`) and is read aloud. Show it to see what is announced.
const shelves: Record<string, string[]> = {
Fiction: ["Dune", "Emma", "Ulysses", "Beloved"],
Science: ["Cosmos", "The Gene"],
Poetry: ["Ariel", "Odes", "Leaves of Grass"],
};
const source = createSceneSource<string>({
load(shelf) {
if (shelf === null) {
return {
id: "library",
heading: "Library",
nodes: [],
edges: [],
clusters: Object.keys(shelves).map((name) => ({
id: name,
label: name,
weight: shelves[name]!.length,
href: `#shelf-${name}`,
drillsInto: name,
shape: "cloud" as const,
marks: [`${shelves[name]!.length} books`], // badges, read with the item
})),
};
}
return {
id: shelf,
heading: shelf,
clusters: [],
edges: [],
nodes: shelves[shelf]!.map((title) => ({
id: title,
label: title,
weight: 1,
href: `#book-${title}`,
drillsInto: null,
shape: "square" as const,
})),
};
},
parentOf: (shelf) => ({ kind: "anchored", focus: null, anchorId: shelf }),
});
export default function Accessibility() {
const [focus, setFocus] = useState<string | null>(null);
const [showOutline, setShowOutline] = useState(true);
return (
<div className={showOutline ? "show-outline" : undefined}>
<div className="demo-toolbar">
<button onClick={() => setShowOutline(!showOutline)}>{showOutline ? "Hide" : "Show"} the outline</button>
</div>
<DataExplorer source={source} focus={focus} onSettle={setFocus} />
</div>
);
}
  • Keyboard. Tab to an entry and press Enter: the explorer enters that item, raising onNodeActivate first exactly as a double-click does, then moves focus to the new scene with a polite announcement.
  • Every node needs an href, so every relationship drawn on the canvas is also an ordinary link. If your data has no pages of its own, use stable in-app URLs.
  • Drawn edges are in the outline too, as links to their far ends.
  • Without WebGL, the canvas is skipped and the outline still works.
  • Reduced motion is respected: no pulse, no grow-in, no animated renderers.