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

Installing button automatically installs spinner and the shared remocn-ui core (lib/remocn-ui/) via registryDependencies. You do not need to install either separately.

States

ButtonState is:

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:

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.

Props

PropTypeDefaultDescription
state
"idle" | "hover" | "press" | "loading" | "success""idle"Current visual state (snap path). State changes snap — no automatic cross-fade.
style
ButtonStyleResolved 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
stringConvenience override for the primary theme token. Merged into theme — saves a theme object for single-token changes.
speed
number1Forwarded to the loading Spinner. Scales the spinner playhead — speed=2 spins twice as fast without changing authored step times.
className
stringOptional className passed to the inner <button> element.