Skip to content
GitSiteEmail

The Chart.Spider component plots several measures on separate axes radiating from a center and connects them into a shape. It is a good fit for stat comparisons, where the silhouette of a build matters more than the exact numbers.

Each point becomes an axis, and each series becomes a shape. A spider needs at least three categories to enclose an area.

import Chart from '@components/Feedback/Chart/Chart';
import { createSignal } from 'solid-js';
const App = () => {
const [stats] = createSignal([
{
label: 'Player',
points: [
{ type: 'strength', value: 13 },
{ type: 'agility', value: 9 },
{ type: 'stamina', value: 16 },
{ type: 'intellect', value: 6 },
{ type: 'spirit', value: 11 },
],
},
]);
return (
<Chart.Spider data={stats()} interactive style={{ height: '20rem' }}>
<Chart.Spider.Web levels={4} style={{ stroke: '#8d8d8d' }} />
<Chart.Spider.Axis />
<Chart.Legend position="bottom" />
</Chart.Spider>
);
};

The first category sits at 12 o’clock, and the rest run clockwise. Rotate the whole chart with startAngle in degrees.

By default the outer ring is the largest value in the data, rounded outward to a readable number. That is usually not what you want for a stat display: a character with low values can still fill the entire web because the scale shrinks to fit them.

maxValue pins the outer ring instead, so the shape has an absolute meaning:

<Chart.Spider data={stats()} maxValue={100} />

With a fixed scale, low values make a small shape and high values nearly fill the web, which makes separate charts easier to compare.

Both are opt-in slots, just like Chart.Grid on a bar chart. Without Chart.Spider.Web there are no rings to read values against, and without Chart.Spider.Axis there are no spokes or category names.

<Chart.Spider.Web levels={5} shape="circle" />

Like line and area charts, a spider defaults to overlay hit-testing. A series here is a single closed path spanning every category, so native SVG hit-testing can only answer “which series” — never “which point.” Instead, the nearest spoke picks the category, and the vertex nearest the pointer’s distance from the center picks the series.

Takes the shared chart props, plus:

Prop NameTypeDefaultDescription
maxValuenumberdata maximumPins the outer ring to a fixed value.
startAnglenumber0Degrees to rotate the first category away from 12 o’clock.

interactive={true} resolves to 'overlay' here, and hover events fire for the nearest vertex. See Types for the shared data and event types.

  • Fewer than three categories renders nothing and warns in development. Two axes cannot enclose a shape.
  • Negative values are treated as zero. A radius below the center has no meaning.
  • Missing categories count as zero, so the shape collapses toward the center on that axis.
Prop NameTypeDefaultDescription
classstring""CSS classes applied to every shape.
styleJSX.CSSProperties{}Inline styles applied to every shape.
fillOpacitynumber0.25Fill opacity. Keep it low when shapes overlap.
strokeWidthChartLength'0.125rem'Outline width.
pointRadiusChartLength'0.1875rem'Vertex marker radius. 0 hides the markers.
Prop NameTypeDefaultDescription
classstring""CSS classes applied to every ring.
styleJSX.CSSProperties{}Inline styles applied to every ring.
levelsnumber4Concentric rings drawn behind the data.
shape'polygon' | 'circle''polygon'Whether rings follow the axes or are true circles.
Prop NameTypeDefaultDescription
classstring""Applied to both the spokes and the category labels.
styleJSX.CSSProperties{}Inline styles applied to the spokes.
linebooleantrueDraws the spoke from the center to each category.
format(category: string) => stringundefinedFormats the category name.

Category labels are HTML placed just outside the outer ring and aligned by quadrant so they extend away from the web instead of over it.

Shared with every chart type. See Shared slots for their props. Chart.Labels places a value just above each vertex.