Pricing

CircularChart

Show proportions as a ring or pie with segments, rounded ends, ring thickness, and hover emphasis.

We are building SnowUI components into interfaces people can use directly in AI conversations. Conversational UI is still in development; this page demonstrates website usage. Supported chat platforms and component versions will be announced after verification. Generating and using SnowUI interfaces inside AI conversations is completely free. It is not a project, uses no project or developer-seat quota, and requires no SnowUI registration, activation, or paid proof.

How to use

Use CircularChart for category proportions in a ring or pie. For goal completion, choose GaugeChart or Progress according to the meaning. Configure colors and labels through public Props.

  • Each data item needs a name and finite positive value. Only the first maxItems valid items appear, and their sum is the percentage denominator. An explicit empty array shows an empty chart.

  • Prefer numeric size. String geometry parses only the numeric portion, so percentages and CSS variables do not provide reliable responsive geometry. Use public center-label, segment-value, and segment-name roles for center content.

  • The default root accessible name follows LocaleProvider through circularChart.name; an explicit aria-label takes priority. Business names, data values, and numeric formatting remain controlled by the caller.

Import

import { CircularChart } from '@snowui-design-system/components';

Usage

Ring and pie shapes

The same sample documentation mix as a slim ring, rounded segments and a solid pie. Thickness changes the shape; transparent gaps reveal the page surface.

Sizes and geometry

Compact, regular and large report tiles. Corner radius and separator width scale from a 160-unit design baseline; ring thickness is supplied explicitly.

Color modes

Compare all three built-in color modes with the same page mix. Choose a brand color to see how the two monochrome modes respond; sequence retains its category colors.

Semantic colors and gradients

A sample documentation review board. The ready segment uses an object gradient, review uses a CSS gradient from the palette, and the remaining segment falls back to the selected color mode.

Ten categories and an Other group

A sample component catalog with ten categories. The compact view groups smaller categories into Other before setting maxItems, preserving the total and accurate percentages.

Center content and formatting

A documentation review report using the default center text styles. Hover a segment to inspect its percentage, or switch to page counts with labelFormatter. The panel and accessible values keep their percentage format.

HoverPanel styles and placement

Inspect sample website traffic with light, dark or surface panels. Try every placement, show the heading, or hide the panel. Center labels remain available when the panel is off.

Hover regions and emphasis

Cell mode bridges the transparent gaps; item mode responds to the visible segments. The center hole stays inactive. Turn off outward growth to keep the geometry steady while retaining data hints.

Appearance direction and playback

Preview an animated catalog reveal for the SnowUI homepage. All eight start directions are available; direction chooses the first segment without rotating the data. Replay and reverse use the component’s own timeline.

Controlled reveal and base layer

Scrub the homepage chart reveal in either direction. Enable the 4% base layer to see the final silhouette, or disable appearance motion to display the complete chart.

Loading, empty and complete reports

A sample weekly documentation review. Loading keeps the chart at its final size and appearance start state; no data gets an explicit message. The complete report is a single 100% segment with a persistent center label.

API Reference

Property Type Default Example Description
data CircularChartItem[] DEFAULT_DATA data={[{ name: 'Reviewed', value: 72 }, { name: 'Remaining', value: 28 }]} Proportional items with required name and finite positive value, plus optional color and percentFormat. Invalid and nonpositive items are removed in input order before taking maxItems. Percentages divide by the visible item sum. Omitted data uses five demo items; an empty or wholly invalid array keeps final dimensions and renders an empty chart.
size number | string 240 size={240} Square chart size, preferably a positive number converted from design pixels to rem. String CSS lengths are passed through, but SVG geometry uses parseFloat without unit conversion; percentages, calc(), and CSS variables are unreliable for geometry.
minWidth number | string `${SECTOR_CHART_MIN_WIDTH}px` minWidth={100} Minimum responsive display width. Numbers follow the same design-pixel-to-rem rule as size; strings are CSS lengths. Defaults to 40 CSS pixels. Set equal to size to prevent shrinking, or lower to permit it. Applies only with enableResponsive=true.
ringThickness number | string 32 ringThickness={48} Nonnegative design-pixel ring thickness. Inner radius is max(0, outer radius minus thickness); outer radius is size / 2 minus hoverThicknessGrowth minus 1. At the outer radius the ring becomes a solid pie. String values parse only their numeric part.
cornerRadius number | string | "auto" "auto" cornerRadius={8} Segment end radius in nonnegative design pixels at a 160×160 reference size, scaled by size / 160. auto uses 4. Final curvature is limited by ring thickness and available segment angle; 0 gives square ends.
separatorWidth number | string | "auto" "auto" separatorWidth={4} Transparent segment gap in nonnegative design pixels at a 160×160 reference size, scaled by size / 160. auto uses 2; 0 removes gaps. Path geometry leaves the actual background visible.
colors (CircularChartColor | undefined)[] — colors={['var(--secondary-green)', undefined, 'var(--secondary-purple)']} Override colors by visible filtered index. Entries accept semantic or CSS colors, variables, linear-gradient strings, or gradient objects with type, angle, and stops. Undefined positions fall back to colorMode; item color wins over the palette. Background utility class names are unsupported.
colorMode CircularChartColorMode "sequence" colorMode="monochromeFade" sequence cycles Primary and nine Secondary colors. monochromeFade reduces one color evenly from 100% on the first item to 20% on the last (one item stays 100%). monochrome uses one color for all items. Item and palette overrides apply in every mode.
color CircularChartColor — color="var(--secondary-purple)" Override the fallback primary color for monochromeFade and monochrome ahead of monochromeColor or mutedMonochromeColor; sequence does not use it. Supports the same solid, semantic, and gradient formats as item color.
monochromeColor CircularChartColor "Primary" monochromeColor="Primary" Fallback primary color only for monochromeFade when color is absent. Supports solid colors and gradients. Opacity descends from 100% to 20%; item color and colors still win.
mutedMonochromeColor CircularChartColor "Black4" mutedMonochromeColor="Black10" Fallback only for monochrome when color is absent. The default Black4 is theme-adaptive and low contrast; segment fill opacity is not reduced further. Item color and colors still win.
hoverThicknessGrowth number | string — hoverThicknessGrowth={4} Nonnegative design pixels added outward on hover or focus. Inner radius and center stay fixed. If omitted, reads legacy hoverScaleSize, then 4. 0 disables geometry growth but retains data hints. String values parse only their numeric part.
startDirection StartDirection "top" startDirection="top-right" Start appearance from the segment crossed by the top, top-right, right, bottom-right, bottom, bottom-left, left, or top-left ray, then continue clockwise. It chooses the first animated segment without rotating data. Several rays may cross one large segment and give the same order.
showBaseLayer boolean false showBaseLayer={true} Show a 4%-opacity layer in each segment’s final color and geometry. Off by default. It neither animates nor receives hits, and does not change actual segments or data.
appearMotion boolean true appearMotion Enable the appearance animation. false shows complete fill immediately and disables replay and reverseAppearance, while leaving hover thickness feedback active.
appearOnView boolean true appearOnView In uncontrolled mode, play once when the chosen anchor reaches a viewport line. Same-origin iframes use position in the outer same-origin page. false leaves playback to instance methods. appearanceProgress takes precedence; scrollAppearance uses a scroll timeline.
appearanceProgress number — appearanceProgress={0.65} Controlled fill progress clamped to 0..1. Caller changes determine the view; automatic and instance playback cannot change it. appearMotion=false still shows full fill. External changes do not call onAppearanceProgressChange.
defaultAppearanceProgress number 0 defaultAppearanceProgress={0} Initial uncontrolled progress clamped to 0..1 and read once. Later Prop changes do not reset motion; controlled appearanceProgress takes precedence. Default 0 is the unfilled outline state.
appearanceDuration number — appearanceDuration={1000} Total duration in milliseconds for instance and automatic playback, default 1000 regardless of segment count. Nonpositive values jump to the end on the next animation frame. Does not change scroll or controlled progress mapping.
appearAnchorId string — appearAnchorId="report-section" ID of the page anchor for appearance. Defaults to the chart root when omitted; an ID that does not exist does not fall back. Affects automatic appearance and scroll timeline, not chart position.
appearAnchorPoint AnchorPoint "top" appearAnchorPoint="center" Anchor top, center, or bottom compared with the viewport trigger line; does not change segment drawing direction.
appearViewportPoint number | "top" | "center" | "bottom" 0.7 appearViewportPoint="center" Viewport trigger line from 0..1 or top=0, center=0.5, bottom=1. Default 0.7 means 70% of viewport height. Together with appearAnchorPoint it sets the trigger or scroll start.
scrollAppearance boolean | { distance?: number | string } false scrollAppearance={{ distance: 320 }} Enable a window-scroll-driven uncontrolled timeline. Same-origin iframes also respond to outer-page scrolling. An object may override distance. Progress advances after the anchor passes the trigger line and reverses on upward scroll. Nested ScrollArea is not observed. appearanceProgress or appearMotion=false takes precedence.
scrollAppearanceDistance number | string 320 scrollAppearanceDistance={320} CSS-pixel distance for scroll progress from 0 to 1, as a number or numeric string, with minimum 1. scrollAppearance.distance takes precedence. Applies only with the scroll timeline; string units are not converted.
onAppearanceProgressChange (progress: number) => void — onAppearanceProgressChange={(progress) => revealPercent = Math.round(progress * 100)} Receives internal progress writes from 0..1, including direct completion during initialization, automatic playback, instance methods, and scrolling. Initial default value itself does not notify; external appearanceProgress changes are not observed. Return values cannot cancel updates.
hoverScaleSize number | string — hoverScaleSize={4} Deprecated alias for hoverThicknessGrowth with the same units and behavior. Used only when hoverThicknessGrowth is omitted. It is not a scale ratio; new code should use hoverThicknessGrowth.
maxItems number 10 maxItems={10} Keep the first N valid items without sorting or merging Other. Integer-clamped to 1..10; 0 or NaN falls back to 10. Percentages use retained items only. Aggregate small categories before passing more than 10; wholly invalid data renders an empty chart.
showCenterLabel boolean true showCenterLabel={false} Show the center content region. false hides dynamic default labels, segment-value and segment-name templates, and static center-label; it does not disable an explicitly enabled HoverPanel.
hoverMode ChartHoverMode "cell" hoverMode="item" cell hits by angle across the ring, preserving the category through transparent gaps while excluding the center hole and outside. item only hits segment paths. Both modes retain keyboard focus hints.
showHoverPanel boolean true showHoverPanel={false} Show a structured panel for the active hover or focus segment while retaining dynamic center labels. false disables it, except that a visible static center-label automatically enables a panel to carry segment information.
hoverPanelVariant ChartHoverPanelVariant "light" hoverPanelVariant="surface" Panel appearance: light glass by default, dark glass, or theme surface. It does not change data or hit behavior.
hoverPanelPlacement ChartHoverPanelPlacement "pointer" hoverPanelPlacement="pin-top-right" pointer follows the pointer. anchor-top and anchor-side position relative to the current pointer point, or chart center for keyboard focus. pin-* fixes to the named chart edge or center, keeps an 8px edge gap, and participates in viewport collision handling.
showHoverPanelLabel boolean false showHoverPanelLabel={true} Show the active segment name above the panel data row. false shows only the row. Visible only with an active item and enabled panel.
percentFormat NumberFormatOptions — percentFormat={{ fractionDigits: 0, locale: "en-US" }} Number format for center and panel percentages and segment aria-label. Supports fractionDigits, locale, and other NumberFormatOptions. Priority: item percentFormat, this Prop, NumberFormatContext, then the default one decimal. labelFormatter changes only center text.
labelFormatter (item: CircularChartItem, percent: number) => string — labelFormatter={(item, percent) => Math.round(percent) + '%\n' + item.name} On hover or focus, receives valid item and percent in 0..100 and returns center text. A newline splits at most two lines for value and name. Not called with static center-label or showCenterLabel=false; panel and segment aria-label percentages remain unchanged.
loading boolean — loading={true} Waiting-for-data state. Keeps final size and center content while holding segments at their appearance start and pausing interaction. When cleared, motion starts according to viewport conditions. Does not render Skeleton; also reads ancestor Frame loading context. Explicit data={[]} does not use demo data.
children Snippet — <CircularChart><Text as="segment-value" /><Text as="segment-name" /></CircularChart> Parameterless center Snippet when showCenterLabel=true. Direct Frame as="center-label" stays visible and enables the panel. Its direct Text as="segment-value" or as="segment-name" children can reuse default center layout with custom text. Direct Text roles outside it are dynamic templates filled by the component. The center is for display, not a toolbar.
class string "" class="report-chart" Additional class on the chart root Frame, empty when omitted. Styles the public root without penetrating internal SVG and label structure.
style string "" style="align-self: center;" Additional inline style on the root Frame after component variables. Use for external layout; prefer size and ringThickness for chart geometry.
enableResponsive boolean true enableResponsive={false} Shrink the chart proportionally when its container is short of width, including in side-by-side flex layouts. minWidth sets the minimum, 40px by default; matching width prevents shrinkage. HoverPanel does not scale. false keeps declared dimensions. Also passed to Frame.
enableContext boolean true enableContext={false} Forward the Frame context switch. Chart size, color, and appearance progress still use their own Props.
enableScaleObserver boolean false enableScaleObserver={false} Forward the legacy Frame size-observer compatibility switch, off by default. It is not percentage chart sizing and is not recommended for new examples.
enableDefaultMotion boolean true enableDefaultMotion={false} Forward Frame outer default motion. It does not own the chart appearance timeline or segment hover thickening, which use appearMotion or appearanceProgress and hoverThicknessGrowth respectively.