Skip to content

Styling and theming

The explorer draws on a canvas, so its colours come from props rather than CSS. Its DOM (the wrapper, the canvas host and the outline) takes your stylesheet as usual.

palette sets the canvas’s own colours: background, grid, label, labelStroke (the outline behind label text), hover, selection, ownership (the ring emphasis) and aggregate (a hollow “N more” cluster). Each is a colour: a 0xRRGGBB number or a CSS string. Start from FALLBACK_PALETTE and override what you need. Pass a new object and the canvas re-tints in place, with no new scene.

An item with a ramp position from 0 to 1 is coloured along the ramp (DEFAULT_RAMP by default). Use it for something ordered: age, size, a score the viewer can read elsewhere. An item without one gets a stable colour of its own, so a missing value never looks like an average one.

A ramp is a list of colour stops, each a 0xRRGGBB number or a CSS string, spread evenly from 0 to 1 like a CSS gradient’s. Two stops make a two-tone scale, three a diverging one. Place a stop with { color, at }, and two stops at the same at make a hard edge between bands. interpolation picks how the colours between stops are blended:

  • oklab (the default) keeps the steps perceptually even, with no muddy middle.
  • srgb is a plain channel mix, which is what a CSS gradient does unless told otherwise.
  • hsl turns the hue the shorter way round between each pair of stops, for a sweep round the colour wheel. DEFAULT_RAMP is one: red through magenta, blue and cyan to green.

The ramp is compared by value, so an inline object is fine. Pass a different one and the canvas re-tints in place, like a palette. The demo switches between a two-tone, a diverging and a banded ramp.

Running the code below: theming.tsx
theming.tsx
import { useState } from "react";
import {
createSceneSource,
DataExplorer,
FALLBACK_PALETTE,
type ExplorerPalette,
type RampColours,
} from "@data-xplorer/core";
// Twelve months of releases; each sits on the colour ramp by how long ago it shipped.
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const source = createSceneSource<null>({
load: () => ({
id: "releases",
heading: "Releases this year",
clusters: [],
nodes: months.map((month, i) => ({
id: month,
label: month,
weight: 3 + ((i * 7) % 10),
href: `#${month}`,
drillsInto: null,
shape: "disc" as const,
ramp: i / 11, // 0 is the start of the ramp, 1 the end
})),
edges: [],
}),
});
// A palette is the canvas's own colours. Pass a new object and the canvas re-tints in place.
const paper: ExplorerPalette = {
...FALLBACK_PALETTE,
background: "#f7f5ef",
grid: "#c9c3b4",
label: "#1f2430",
labelStroke: "#f7f5ef",
selection: "#1d4ed8",
hover: "#475569",
};
// A ramp is colour stops, blended in OKLab unless you say otherwise. Switching re-tints in place.
const ramps: Record<string, RampColours> = {
"Teal to violet": { stops: ["#14b8a6", "#8b5cf6"] },
"Gold to red": { stops: ["#facc15", "#dc2626"] },
"Cool, neutral, warm": { stops: ["#3b82f6", "#e5e7eb", "#f97316"] },
// Two stops at the same `at` make a hard edge: the first half of the year grey, the second orange.
Banded: {
stops: ["#94a3b8", { color: "#94a3b8", at: 0.5 }, { color: "#f97316", at: 0.5 }, "#f97316"],
interpolation: "srgb",
},
};
export default function Theming() {
const [light, setLight] = useState(false);
const [ramp, setRamp] = useState("Teal to violet");
return (
<>
<div className="demo-toolbar">
<button onClick={() => setLight(!light)}>{light ? "Dark" : "Light"} palette</button>
{Object.keys(ramps).map((name) => (
<button key={name} aria-pressed={ramp === name} onClick={() => setRamp(name)}>
{name}
</button>
))}
</div>
<DataExplorer
source={source}
focus={null}
palette={light ? paper : FALLBACK_PALETTE}
ramp={ramps[ramp]}
/>
</>
);
}

The explorer needs no stylesheet. It sets inline only what it cannot work without: the canvas fills its container’s width and owns its touch gestures, and the outline is visually hidden but read aloud. If nothing gives the canvas a height, it takes 480 px. To style it, target:

Class What it is
.data-explorer The view’s wrapper.
.data-explorer__surface The canvas host. Give it (or its container) a height; borders, background and cursor are yours.
.visually-hidden The outline, already hidden inline.

Your rules win, because the inline styles set only what the explorer needs, at the values a styled page would use anyway. This site sizes every demo with one rule on .data-explorer__surface.