Fee Selector
Three tier cards — Economy, Standard, Priority — with live sat/vB rates and confirmation ETAs. The primary ring glides between selections on the shared-layout spring; loading shows skeleton rows; stale rates raise an amber refresh bar and dim the cards.
Tier selected
One specimen per selection. The ring is a layoutId border, so in the live product it slides — it never blinks.
<FeeSelector tiers={tiers} selected="economy" />--ch-primary--ch-surface--ch-border
2 sat/vB · ~2 hours — patient consolidation.
<FeeSelector tiers={tiers} selected="standard" />--ch-primary--ch-surface--ch-border
6 sat/vB · ~30 minutes — the default.
<FeeSelector tiers={tiers} selected="priority" />--ch-primary--ch-surface--ch-border
14 sat/vB · ~10 minutes — next-block intent.
Custom rate
Power users type their own sat/vB. The row is a fourth radio; the numeric input stays editable without stealing the selection click.
<FeeSelector tiers={tiers} selected="custom" custom={{ satPerVb: 11 }} />--ch-primary--ch-bg-raised--ch-font-family-mono
Custom row active at 11 sat/vB — between standard and priority.
Loading and stale
Loading renders three skeleton rows at tier-card height, so nothing jumps when rates land. Stale keeps the last-known tiers usable but dimmed under an amber refresh bar — old rates are a warning, not an error.
<FeeSelector tiers={tiers} selected="standard" state="loading" />--ch-bg-raised--ch-radius-lg
Fetching estimates from the connected node.
<FeeSelector tiers={tiers} selected="standard" state="stale" staleMessage="Rates updated 4m ago" />--ch-warning--ch-warning-muted--ch-border
Rates aged past the refresh window; cards dim to 70% and the bar offers Refresh.
Live selection
Interactive — click between tiers and the custom row to watch the ring glide on springs.glide, and edit the custom rate.
<FeeSelector tiers={tiers} selected={selected} onSelect={setSelected} custom={{ satPerVb }} onCustomChange={setSatPerVb} />--ch-primary--ch-surface-raised--ch-focus
Selection and custom rate held in local state; everything else identical to the forced specimens.
Across themes
Standard selected under dark, light, and Harbor Mode — the ring stays primary; only the surfaces shift.
<FeeSelector tiers={tiers} selected="standard" />--ch-primary--ch-surface--ch-border--ch-fg-muted