You Might Also Like
Pie Chart — HTML CSS JS SVG Pie Chart (No Library)
Pie Chart · Charts · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Pie Chart — SVG Arc-Path Pie Chart with Hover Tooltips & Toggleable Legend

A pie chart shows part-to-whole composition at a glance — what share each source, category, or segment contributes to a total. This snippet builds a complete, interactive pie chart in plain HTML, CSS, SVG, and vanilla JavaScript, with no charting library: each slice is a real SVG <path> wedge computed from the data, with hover tooltips, a legend that toggles slices on and off, and percentages that recalculate live.
Real SVG wedges, computed with trigonometry
Each slice is an SVG path made of three commands: move to the centre, line out to the start of the arc, then an elliptical A (arc) command sweeping to the end of the slice, then close. The start and end points are found with point(frac), which converts a fraction of the circle (0–1) into x/y coordinates using Math.cos/Math.sin, offset by −90° so the chart starts at twelve o'clock like every pie chart people expect. The arc's large-arc-flag is set to 1 whenever a slice spans more than half the circle, which is the one detail that trips people up when drawing arcs by hand — get it wrong and big slices render inverted.
Why SVG paths instead of conic-gradient
You can fake a pie with a single conic-gradient, but that gives you one flat element with no per-slice interactivity — no hover target, no individual slice to highlight or pull out, no accessible structure. Drawing each slice as its own path means every slice is a real DOM node you can attach a tooltip to, fade on hover, animate independently, or click. That interactivity is the whole point of a chart, so the small amount of arc math is worth it.
A legend that toggles slices
The legend lists every series with its colour swatch and value. Clicking a legend row hides or shows that slice, and the chart re-renders with the remaining slices re-proportioned to the new total — the same behaviour as Chart.js and every dashboard charting tool. A guard prevents hiding the last visible slice (an empty pie is meaningless), and hidden rows stay in the legend, dimmed, so they can be toggled back on. Because the percentages derive from the live total, hiding a slice recalculates everyone else's share automatically.
Tooltips positioned to the cursor
Hovering a slice shows a tooltip with the series name, its raw value, and its percentage, positioned at the mouse using getBoundingClientRect to convert the page coordinates into offsets within the card. The tooltip is pointer-events: none so it never flickers by intercepting its own hover, and it follows the cursor smoothly via a single mousemove listener on the SVG with event delegation through closest('.pc-slice').
Data-driven and drop-in
The entire chart renders from a DATA array of { name, value, color } — swap in your analytics, budget, or survey numbers and everything (slices, legend, total, percentages) updates. Because it's compact and dependency-free, it drops into any dashboard or report, and the arc math is a clear reference for understanding how SVG pie and donut charts are actually drawn.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't have to derive the arc trigonometry by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how the point function converts a 0-1 fraction of the circle into an x/y coordinate with the -90 degree offset, and why the large-arc-flag in slicePath must switch to 1 once a slice exceeds half the circle. The same assistant can help optimize it, for example checking whether recomputing every slice's path string on every legend toggle is cheap enough for a chart with many more than five categories, or whether the mousemove tooltip handler could be throttled without hurting responsiveness. It's also useful for extending the effect: ask it to add an animated transition when slices are toggled instead of an instant redraw, turn it into a donut chart by punching an inner radius hole, or support clicking a slice to pull it outward like an exploded pie chart. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build an interactive pie chart in plain HTML, CSS, and vanilla JavaScript using hand-drawn SVG path arcs — no charting library, no CSS conic-gradient.
Requirements:
- A data array of objects each with a name, a numeric value, and a color, rendered into an SVG donut of wedges plus a legend listing every entry with its color swatch and value.
- Write a function that converts a fraction from 0 to 1 into an x/y point on a circle of a given radius, using cosine and sine with the angle offset by -90 degrees so a fraction of 0 lands at the twelve o'clock position rather than SVG's default three o'clock.
- Write a function that builds one slice's SVG path data as: move to the circle's center, draw a line out to the arc's start point, draw an elliptical arc command to the arc's end point, then close the path — and make sure the arc command's large-arc-flag is computed as 1 whenever that slice's angular span exceeds half the full circle, otherwise 0.
- Compute each slice's start and end fraction by accumulating each data entry's share of the running total (value divided by the sum of all currently visible values) in order, so slices tile the whole circle with no gaps or overlaps.
- Clicking a legend row must toggle that entry's slice out of the chart (hiding its path and dimming its legend row) and re-render every remaining slice re-proportioned against the new total of only the visible entries — but must never allow the very last visible slice to be hidden.
- Add a tooltip that follows the mouse while hovering any slice, showing that slice's name, raw value, and percentage of the current visible total, positioned using getBoundingClientRect so it tracks correctly relative to the chart's container regardless of page scroll.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Paste HTML, CSS, and JSA pie chart renders with five slices, a legend, and a running total of visits.
- 2Hover a sliceMove over any wedge to see a tooltip with its name, value, and percentage of the total.
- 3Toggle slicesClick a legend row to hide that slice; the remaining slices re-proportion and the total updates.
- 4Swap in your dataReplace the DATA array with your own { name, value, color } items — slices, legend, and percentages all derive from it.
- 5Restyle itChange the colours, radius (R), or card styling; the arc math adapts to any radius automatically.
- 6Wire to an APIFetch your figures, map them to the DATA shape, and call render() to draw the live chart.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Each slice is an SVG <path> built from three commands: move to the centre, line to the slice's start point on the circle, then an elliptical arc (A) to its end point, then close (Z). The start/end points come from point(frac), which converts a fraction of the circle into x/y with Math.cos/Math.sin offset by −90° so the chart begins at twelve o'clock. The arc's large-arc-flag is set to 1 for any slice spanning more than half the circle.
A conic-gradient renders a pie as a single flat element with no per-slice interactivity — you can't hover, highlight, pull out, or animate an individual slice. Drawing each slice as its own <path> makes every slice a real DOM node you can attach tooltips and click handlers to, which is the entire value of an interactive chart. The arc math is the small cost of that interactivity.
Clicking a legend row flips a flag in the hidden map and calls render(), which recomputes the total from only the visible slices and redraws each remaining wedge proportioned to that new total. Because percentages and the running total both derive from the live sum, hiding one slice automatically re-proportions the rest — the same behaviour as professional charting libraries.
Edit the DATA array — each entry is { name, value, color }. Add, remove, or change entries and the slices, legend, total, and percentages all derive from it on the next render(). For real data, fetch your numbers, map them into that shape, and call render(); the arc math handles any number of slices and any values.
In React, hold the data and hidden state in useState and render the slices/legend from .map() with onClick toggles; in Vue, use v-for with ref state; in Angular, use *ngFor with component properties. The point()/slicePath() arc math is framework-agnostic — only the state and event wiring move into the framework, and the SVG paths render identically.