KQ-1255 · RENEW/LOOP

Renew Loop

An auto-renew switch whose icon is the renewal: switched on, two arc arrows chase round the ring on springs.glide until their heads catch the other's tails and lock into a closed ring on springs.snap, the heads folding to small chevrons as the ring takes the accent, while a split-flap readout beside the label turns over cell by cell to the renewal date. Switched off, the ring breaks at the top, the arrows coast apart under friction on an inertia decay and the readout flips back to the day access ends. Dates come only from props, read in UTC; Space and Enter toggle it, and a polite status speaks the new date.

KQ-1255 · RENEW/LOOP

Fernworks Pro

Waylight Pay · €12 / month

Renews 15 Nov, then every month.

auto-renew on · next charge €12 on 15 Nov

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/renew-loop

Props

pressed / defaultPressed
boolean
default false
Controlled and initial state; true while the plan renews by itself.
onPressedChange
(pressed: boolean) => void
default —
Fires from the press that changed it, with the new state.
renewsOn
Date | number | string
default renewedOn plus one period
The next renewal date, when your billing system already knows it.
renewedOn
Date | number | string
default "2026-10-15"
The day the current term began: the last renewal, or the purchase.
period
"month" | "quarter" | "year"
default "month"
The billing period: how far each renewal carries the plan.
label
string
default "Auto-renew"
What the switch controls; the button's accessible name.
renewsLabel
string
default "Renews"
The word before the date while on.
endsLabel
string
default "Ends"
The word before the date while off.
formatDate
(date: Date) => string
default "15 Nov" in UTC
How a date is written in the readout and the description.
chase
number
default 240
How far the arrows chase before their heads lock, in degrees.
flip
number
default 90
How long one flap takes to fall, in ms.
friction
number
default 0.5
How quickly the released arrows coast to a stop, 0 (they glide on) to 1 (they stop short).
compact
boolean
default false
Ring only; the label becomes the accessible name and the date its description and title.
size
"sm" | "md" | "lg"
default "md"
Pill height 32, 36 or 44px with the readout scaled to match.
accent
string
default var(--accent-bright)
The closed ring's colour, any CSS colour.
sound
boolean
default false
A ratchet tick per 30° of spin, a snap when the heads lock or the ring breaks, a faint tick per flap. Only after a press.
disabled
boolean
default false
Greys the switch out and ignores presses and hover.
className
string
default —
Extra classes for the root, which wraps the button.