Button
A button whose visual state is a pure function of the timeline
A state atom whose appearance (idle, hover, press, loading, success) is a pure function of the state prop. Pass a state directly or drive it from the Remotion timeline via useCurrentState. The component reads no frame — only the state value you give it.
$ pnpm dlx shadcn@latest add @remocn/buttonStates
ButtonState is:
type ButtonState =
| "idle" // resting
| "hover" // lifted + background shift
| "press" // scale down + darken
| "loading" // renders <Spinner />
| "success" // renders a static checkmark, background fills primaryloading composes <Spinner /> in place of the label. success renders a static checkmark SVG. Both loading and success hide the label text.
Snap usage (simple path)
Pass state directly — the component snaps instantly to that visual. Useful for static previews or when you drive state from your own logic:
import { Button } from "@/components/remocn/button";
export const Scene = () => <Button state="loading" />;To drive state from the timeline, use useCurrentState:
import { useCurrentState } from "@/lib/remocn-ui";
import { Button } from "@/components/remocn/button";
export const Scene = () => {
const state = useCurrentState(
[
{ at: 8, state: "hover" },
{ at: 20, state: "press" },
{ at: 35, state: "loading" },
{ at: 70, state: "success" },
],
"idle",
);
return <Button label="Continue" state={state} />;
};Each at is a Sequence-local authored frame. State persists between steps: hover at frame 8 keeps the button lifted until press fires at frame 20. See Concepts for the full useCurrentState API.
Smooth transitions (opt-in)
State changes via state snap with no cross-fade. For animated transitions, use useButtonTransition from the copied use-button-transition.ts file. It reads the frame, interpolates between state presets, and returns a resolved ButtonStyle — pass it to the style prop:
import { Button } from "@/components/remocn/button";
import { useButtonTransition } from "@/components/remocn/use-button-transition";
export const Scene = () => {
const style = useButtonTransition([
{ at: 12, state: "hover" },
{ at: 30, state: "press" },
{ at: 48, state: "loading", duration: 6 },
{ at: 96, state: "success", duration: 16 },
]);
return <Button label="Continue" style={style} />;
};The duration field on each step overrides the file's DEFAULT_DURATION for that specific transition. To globally tune timing and easing, edit use-button-transition.ts directly in your project — that file is yours (shadcn "own your code" philosophy).
style takes precedence over state when both are provided.
Props10
| Prop | Type | Default |
|---|---|---|
| state | "idle" | "hover" | "press" | "loading" | "success""idle" Current visual state (snap path). State changes snap — no automatic cross-fade. | |
| style | ButtonStyle— Resolved animated visual (smooth path). Pass an interpolated ButtonStyle from useButtonTransition. Takes precedence over state when provided. | |
| label | string"Continue" Button label text. Hidden during loading and success states. | |
| variant | "default" | "secondary" | "destructive" | "outline" | "ghost""default" Visual variant. Matches shadcn button variant names. | |
| size | "sm" | "default" | "lg""default" Button height and padding. sm=32px, default=40px, lg=48px. | |
| 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. | |
| primary | string— Convenience override for the primary theme token. Merged into theme — saves a theme object for single-token changes. | |
| speed | number1 Forwarded to the loading Spinner. Scales the spinner playhead — speed=2 spins twice as fast without changing authored step times. | |
| className | string— Optional className passed to the inner <button> element. | |
- state"idle" | "hover" | "press" | "loading" | "success"
Current visual state (snap path). State changes snap — no automatic cross-fade.
Default
"idle" - styleButtonStyle
Resolved animated visual (smooth path). Pass an interpolated ButtonStyle from useButtonTransition. Takes precedence over state when provided.
- labelstring
Button label text. Hidden during loading and success states.
Default
"Continue" - variant"default" | "secondary" | "destructive" | "outline" | "ghost"
Visual variant. Matches shadcn button variant names.
Default
"default" - size"sm" | "default" | "lg"
Button height and padding. sm=32px, default=40px, lg=48px.
Default
"default" - 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" - primarystring
Convenience override for the primary theme token. Merged into theme — saves a theme object for single-token changes.
- speednumber
Forwarded to the loading Spinner. Scales the spinner playhead — speed=2 spins twice as fast without changing authored step times.
Default
1 - classNamestring
Optional className passed to the inner <button> element.