KQ-637 · GAIN/LOSS

Gain Loss Bar

A holding's day measured from a centre line: gains grow right in success, losses grow left in danger, all scaled against the largest move so the longest bar reaches the edge. Bars unroll out of the axis on glide with a cascade on the first paint only, and the sort control re-orders the rows with FLIP on glide so a row travels to its place rather than blinking there. The sort is a radiogroup with a roving tabindex — arrows step, Home and End jump, Space selects.

KQ-637 · GAIN/LOSS
Fernworks Capital · positions todayNet+$2,410
  • CBK, up $2,180, 4.2 percent
  • BSN, up $1,240, 6.8 percent
  • WAY, up $1,035, 2.6 percent
  • FLD, unchanged
  • FRN, down $430, 3.1 percent
  • GGE, down $1,615, 9.4 percent
Sorted by best, net +$2,410 across 6 holdings

Sort best · basis amount · net +$2,410 · 6 holdings

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/gain-loss

Props

holdings
GainLossHolding[]
default
The set: id, label, the money moved and the same move in percent.
sort / defaultSort
"best" | "worst" | "name"
default "best"
Controlled or initial sort; changing it re-orders the rows with FLIP.
onSortChange
(sort: GainLossSort) => void
default
Fires from the click or key that changed the sort.
basis
"amount" | "percent"
default "amount"
Which figure the bars and row readouts measure; changing it re-scales every bar at once.
format
(value: number) => string
default USD, 0dp
Formats every money figure, including the net.
label
React.ReactNode
default
Visible heading; omit it and pass aria-label.