Compact SVG donut for share-of-total visuals like release channels and quota usage.
DonutChart visualises share-of-total values inside a circular ring. Its rounded, separated segments use the shared blue and aqua chart palette by default. It uses pure SVG without any chart engine and stays accessible through an explicit label.
Pair with a Legend to caption colour mapping.
<DonutChart
data={[
{ label: "Stable", value: 62 },
{ label: "Beta", value: 28 },
{ label: "Alpha", value: 10 },
]}
label="Release channel mix"
/>import { DonutChart } from "@froggdesign/enter-ui-react";Use segmented for thin rings with flat ends and visible gaps. Pair it with
Legend variant="bars" in the same item order so the default colors match.
The centre label uses shared typography and layout components.
A segmented donut and share bars use matching series colors.
import { DonutChart, HStack, Legend, Text, VStack } from "@froggdesign/enter-ui-react";
export function Allocation() {
return (
<VStack align="stretch" gap={24}>
<HStack justify="center">
<DonutChart
variant="segmented"
size={136}
strokeWidth={7}
data={[
{ label: "BTC", value: 49.7 },
{ label: "ETH", value: 21.6 },
{ label: "SOL", value: 13.8 },
{ label: "USDC", value: 9.2 },
{ label: "AVAX", value: 5.7 },
]}
label="Portfolio composition"
centerLabel={
<VStack gap={2}>
<Text as="span" size="xs" tone="muted">Assets</Text>
<Text as="span" size="lg" weight="bold">5</Text>
</VStack>
}
/>
</HStack>
<Legend
variant="bars"
items={[
{ label: "BTC", share: 49.7, value: "49.7%" },
{ label: "ETH", share: 21.6, value: "21.6%" },
{ label: "SOL", share: 13.8, value: "13.8%" },
{ label: "USDC", share: 9.2, value: "9.2%" },
{ label: "AVAX", share: 5.7, value: "5.7%" },
]}
/>
</VStack>
);
}Pass finite numbers. Values are normalized against the total; they do not need
to add up to 100. For example, values 2 and 1 produce shares of about 66.7%
and 33.3%. Negative values are treated as zero. Empty data or a total of zero
renders only the background ring; centerLabel can still be shown.
Legend does not calculate percentages from the chart data. Compute each
share as Math.max(0, value) / total * 100 when the total is positive, or
zero otherwise. Keep the chart and legend in the same order, and pass matching
color values to both when using custom colors.
Provide an aria-label or label so screen readers announce the chart. When none is given, the SVG is marked aria-hidden for decorative use. Include a visible Legend or a textual summary with labels and values so the data is available without relying on color. The chart itself is static and has no keyboard controls.
variant: default (rounded slices) or segmented (flat ends with gaps and a five-color palette matching Legend bars).
data: array of { value, color?, label? } slices.
size: outer pixel size (default 120).
strokeWidth: ring thickness in the SVG's 100 × 100 viewBox (default 14). The rendered thickness is strokeWidth × size / 100 pixels; size={136} with strokeWidth={7} produces a ring about 9.52px thick.
centerLabel: optional ReactNode rendered in the centre.
label: accessible chart name. aria-label takes precedence when both are supplied.
Other SVG attributes and the forwarded ref apply to the SVG; className applies to the outer wrapper.
Every exported component accepts className when it renders an element. EnterUI styles use .eui-* classes and --eui-* variables mapped from FroggDesign theme tokens.