Skip to main content
Pass any subset of GraphTheme to the theme prop. The value is deep-merged with DEFAULT_THEME, so you only override what you care about.
<ForceGraph
  theme={{
    node:    { color: "#0ea5e9", hoverColor: "#f97316" },
    link:    { defaultAlpha: 0.55, dimRgbTuple: "100,116,139" },
    cluster: { intraLinkDistance: 100, interLinkDistance: 320, strength: 0.22 },
    label:   { zoomGrowthCap: 2 },
  }}
  nodes={nodes}
  edges={edges}
/>

Theme reference

KeyTypeDefaultDescription
radiusnumber4Visible node radius in graph units.
fontSizenumber8Label font size at zoom 1×.
labelGapnumber3Vertical gap between node and label.
labelColorstringoklch(0.95 0 0)Label text colour.
colorstring#ffffffDefault fill.
hoverColorstringoklch(0.5544 0.1146 158.24)Fill while hovered.
KeyTypeDefaultDescription
fontSizenumber6Edge label size at zoom 1×.
labelPaddingXnumber3Horizontal padding of label rect.
labelPaddingYnumber1Vertical padding of label rect.
labelBackgroundColorstringtransparentBackground fill of the label rect.
KeyTypeDefaultDescription
opacityMinZoomnumber1.2Zoom at which labels start fading in.
opacityMaxZoomnumber1.7Zoom at which labels reach full opacity.
zoomGrowthCapnumber3Above this zoom, labels stop growing in screen pixels and zoom de-clutters.
KeyTypeDefaultDescription
labelShiftYnumber2Vertical shift when hovered.
hiddenLabelOpacitynumber1Target opacity for labels that were hidden.
animationDurationMsnumber150Fade-in / fade-out duration.
highlightOpacityBoostnumber0.6Floor for label opacity while hovered.
dimOpacitynumber0.15Multiplier applied to non-hovered nodes.
KeyTypeDefaultDescription
linkDistancenumber120Fallback target link length when clustering is disabled.
chargeStrengthnumber-250forceManyBody strength (negative = repulsion).
chargeDistanceMaxnumber500Maximum distance over which charge applies.
alphaDecaynumber0.015Simulation cooldown rate.
velocityDecaynumber0.6Per-tick velocity damping.
boundaryStrengthnumber0.01forceX / forceY strength pulling toward (0, 0).
The three knobs that most affect “nodes feel cramped at high zoom” are chargeStrength (push apart harder), boundaryStrength (let the layout breathe further from origin), and node.radius (raise the collision floor). Reasonable ranges: chargeStrength between -30 and -500, boundaryStrength between 0.01 and 0.3.
KeyTypeDefaultDescription
intraLinkDistancenumber120Target link length between two nodes in the same community.
interLinkDistancenumber280Target link length for cross-community bridges.
strengthnumber0.14Centroid pull strength (alpha-scaled on top of this).
KeyTypeDefaultDescription
centerAnimationDurationnumber300Pan animation duration (ms).
targetZoomnumber2Zoom level after a node or edge click.
animationDurationnumber300(edgeClick) Pan animation duration (ms).
paddingnumber80(edgeClick) Padding around the edge.
KeyTypeDefault
fontFamilystringSatoshi, Inter, ui-sans-serif, system-ui, sans-serif

CSS variables

The package only styles the container and the optional zoom indicator — everything inside the canvas is painted from the theme. Override on .cg-root.
VariableDefault (light)Purpose
--cg-muted-fgoklch(0.35 0.02 99.4974)Empty-state and zoom-label text.
--cg-zoom-bgtransparentZoom indicator background.
--cg-zoom-fgvar(--cg-muted-fg)Zoom indicator text.
The zoom indicator picks up cg-zoom-label--{position} modifier classes — override any of them in your own CSS to retarget placement.