Progress
A progress bar that fills along a scripted numeric value timeline
A value-channel atom whose fill (0–100) is a pure function of the value prop or an interpolated ProgressStyle from useProgressTransition. The component reads no frame — only the value you give it. This is the value-channel variant of the primitive pattern: instead of a string-state timeline it drives a numeric fill channel directly, the same deviation used by the Cursor primitive.
$ pnpm dlx shadcn@latest add @remocn/progressValue steps
Instead of a string-state timeline, useProgressTransition takes an array of ProgressStep objects that describe a scripted fill path:
interface ProgressStep {
at: number; // LOCAL (Sequence-relative) authored frame the bar finishes reaching `value`
value: number; // Target fill percentage 0–100
duration?: number; // Frames the move INTO this value takes. Omitted → DEFAULT_DURATION (24)
easing?: EasingName; // Override easing for the move into this value. Default "out"
}at is the arrival frame — the frame when the bar finishes its fill. The move itself runs over [at - duration, at). Before the first arrival, the bar holds at the first step's value.
Numeric-channel deviation
Progress differs from state atoms (Button, Toast, etc.) in one key way: there is no string state union and no useCurrentState snap path. The bar's visual is always numeric — a fill percentage — so useProgressTransition folds the value path directly into a ProgressStyle. The snap equivalent is simply passing a fixed value prop.
To model a pause or stall, add two steps at the same value with a gap between their at frames. The bar reaches the stall value and holds until the next step fires:
useProgressTransition([
{ at: 0, value: 0 },
{ at: 40, value: 62, duration: 36 }, // fills to 62, arrives frame 40
{ at: 130, value: 100, duration: 30 }, // resumes after ~60-frame stall
]);Snap usage
Pass value directly — the component snaps instantly to that fill. Useful for static previews or when you drive value from your own logic:
import { Progress } from "@/components/remocn/progress";
export const Scene = () => (
<div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" }}>
<Progress value={62} showLabel width={320} />
</div>
);Smooth transitions
Fill changes via value snap with no tween. For an animated fill, use useProgressTransition from the copied use-progress-transition.ts file. It reads the frame, interpolates between value steps, and returns a resolved ProgressStyle — pass it to the style prop:
import { Progress } from "@/components/remocn/progress";
import { useProgressTransition } from "@/components/remocn/use-progress-transition";
export const Scene = () => {
const style = useProgressTransition([
{ at: 0, value: 0 },
{ at: 40, value: 62, duration: 36 },
{ at: 130, value: 100, duration: 30 },
]);
return (
<div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" }}>
<Progress style={style} showLabel width={320} />
</div>
);
};The duration field on each step overrides the file's DEFAULT_DURATION (= 24) for that specific move. The default easing per step is "out" — the bar decelerates as it nears the target value. To globally tune timing and easing, edit use-progress-transition.ts directly in your project — that file is yours (shadcn "own your code" philosophy).
style takes precedence over value when both are provided.
Props7
| Prop | Type | Default |
|---|---|---|
| value | number0 Fill percentage 0–100 (snap path). Clamped to [0, 100]. Ignored when style is provided. | |
| style | ProgressStyle— Resolved animated visual (smooth path). Pass an interpolated ProgressStyle from useProgressTransition. Takes precedence over value when provided. | |
| width | number320 Track width in px. | |
| showLabel | booleanfalse When true, renders the floored fill percentage to the right of the track in tabular-nums. | |
| theme | Partial<RemocnTheme>— Per-component theme override. Merges with the active RemocnUIProvider theme and the mode defaults. Must be concrete oklch/hex/rgb values — not CSS custom properties. | |
| mode | "light" | "dark""light" Sets the base palette. Overrides the mode on RemocnUIProvider when both are present. | |
| className | string— Optional className applied to the outer wrapper element. | |
- valuenumber
Fill percentage 0–100 (snap path). Clamped to [0, 100]. Ignored when style is provided.
Default
0 - styleProgressStyle
Resolved animated visual (smooth path). Pass an interpolated ProgressStyle from useProgressTransition. Takes precedence over value when provided.
- widthnumber
Track width in px.
Default
320 - showLabelboolean
When true, renders the floored fill percentage to the right of the track in tabular-nums.
Default
false - themePartial<RemocnTheme>
Per-component theme override. Merges with the active RemocnUIProvider theme and the mode defaults. Must be concrete oklch/hex/rgb values — not CSS custom properties.
- mode"light" | "dark"
Sets the base palette. Overrides the mode on RemocnUIProvider when both are present.
Default
"light" - classNamestring
Optional className applied to the outer wrapper element.