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.

Installation
$ pnpm dlx shadcn@latest add @remocn/button

States

ButtonState is:

ts
type ButtonState =
  | "idle"     // resting
  | "hover"    // lifted + background shift
  | "press"    // scale down + darken
  | "loading"  // renders <Spinner />
  | "success"  // renders a static checkmark, background fills primary

loading 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:

tsx
import { Button } from "@/components/remocn/button";
 
export const Scene = () => <Button state="loading" />;

To drive state from the timeline, use useCurrentState:

tsx
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:

tsx
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

PropTypeDefault
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.

    Default1

  • classNamestring

    Optional className passed to the inner <button> element.