Theming & styling
Every colour on the canvas is driven by a CSS custom property (--pvt-*), so theming is just CSS. Pivotick ships light and dark themes — flip between them by setting data-theme on the graph root — and you define your own the same way: a [data-theme] block that sets the variables you care about. When a variable doesn't cover something, the rendered SVG is plain, classed elements (.pvt-node, .pvt-edge-group path) you can style directly.
Switch the theme below. Light and Dark are built in; Brand is a custom theme defined entirely in CSS — a handful of variables for the palette, plus a few class hooks for effects the variables don't expose (a neon glow on nodes and edges, dashed links, bolder labels).
css
/* A custom "brand" theme. Set data-theme="brand" on the graph root (.pivotick)
and these variables cascade into the canvas — nodes, edges, labels, background
and grid all recolour, with no re-render. ('light' and 'dark' ship with
Pivotick and need none of this — they are just other data-theme values.) */
.pivotick[data-theme='brand'] {
--pvt-bg: #141038; /* deep indigo canvas */
--pvt-graph-grid-color: #241d5c; /* dotted grid */
--pvt-node-color: #ff5d8f; /* vivid pink node fill */
--pvt-node-stroke: #ffd166; /* gold ring */
--pvt-node-stroke-width: 2.5; /* thicker ring */
--pvt-node-text-color: #ffffff; /* label (rendered inside the node) */
--pvt-edge-stroke: #8b7dff; /* lavender edges */
}css
/* Variables cover colours; for effects they don't expose, reach the rendered SVG
through its classes. Here the brand gets a neon glow on nodes and edges, dashed
links, and bolder labels — none of which is a variable. */
.pivotick[data-theme='brand'] .pvt-node .node {
filter: drop-shadow(0 0 5px rgba(255, 93, 143, 0.75));
}
.pivotick[data-theme='brand'] .pvt-node-label {
font-weight: 800;
letter-spacing: 0.6px;
}
.pivotick[data-theme='brand'] .pvt-edge-group path {
stroke-dasharray: 6 5;
filter: drop-shadow(0 0 2px rgba(139, 125, 255, 0.9));
}js
// Switch a single graph's theme at runtime by setting data-theme on its root
// (the .pivotick element). 'light' and 'dark' ship with Pivotick; 'brand' is a
// custom theme defined in CSS (theme.css). No re-render — the variables cascade
// in immediately.
function applyTheme(container, theme) {
container.querySelector('.pivotick')?.setAttribute('data-theme', theme)
}js
const options = {
render: {
defaultNodeStyle: {
size: 22,
// Only set the label. Leaving colour/stroke/text-colour unset keeps the
// built-in defaults, which resolve to CSS variables (--pvt-node-color,
// --pvt-node-stroke, --pvt-node-text-color) — that is what makes the
// graph re-theme purely from CSS. Hard-code a colour here and it would
// win over the variables.
text: (node) => node.getData()?.label
}
}
}js
// Short labels sit inside the nodes, so the label colour is themed too.
const data = {
nodes: [
{ id: 'ada', data: { label: 'Ada' } },
{ id: 'bo', data: { label: 'Bo' } },
{ id: 'cy', data: { label: 'Cy' } },
{ id: 'deb', data: { label: 'Deb' } },
{ id: 'eve', data: { label: 'Eve' } },
{ id: 'fin', data: { label: 'Fin' } },
{ id: 'gil', data: { label: 'Gil' } }
],
edges: [
{ from: 'ada', to: 'bo' },
{ from: 'ada', to: 'cy' },
{ from: 'bo', to: 'deb' },
{ from: 'cy', to: 'deb' },
{ from: 'deb', to: 'eve' },
{ from: 'eve', to: 'fin' },
{ from: 'eve', to: 'gil' },
{ from: 'fin', to: 'gil' }
]
}