KQ-631 · HOLDINGS/RING

Holdings Ring

An allocation ring that re-proportions rather than redraws: every asset is one stroked circle whose pathLength is its share and whose pathOffset is its start on the rim, so adding or removing an asset animates two numbers on glide and the whole ring settles as one body. Segments draw in on a cascade at mount and shrink away on the exit ease, while pointing at one lifts it along its own mid angle on snap and cross-fades the hub to that asset's amount and share. The SVG is decorative; the legend under it is a real radiogroup with a roving tabindex where arrows step, Home and End jump, Space selects and Escape hands the hub back to the total.

KQ-631 · HOLDINGS/RING
Waylight Pay · portfolio mix
Total$45,3504 assets
4 assets, total $45,350.

Mix 4 assets · Total 45,350

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/holdings-ring

Props

assets
RingAsset[]
default
The mix clockwise from twelve o'clock: id, label and value. Non-positive assets are dropped.
value / defaultValue
string | null
default null
Controlled or initial selected asset id; null reads the portfolio total.
onValueChange
(id: string | null) => void
default
Fires from the click, key or Escape that changed the selection.
format
(value: number) => string
default Intl.NumberFormat("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 0 })
Formats every amount. The default pins an explicit locale so server and client agree.
label
React.ReactNode
default
Visible group heading; omit it and pass aria-label to name the ring invisibly.
totalLabel
string
default "Total"
Caption over the hub figure while nothing is selected.
thickness
number
default 13
Segment stroke width in the 120-unit viewBox.