Siteplane UI

Animated Buttons

Buttons with hover motion, such as a fill that sweeps in or an arrow that expands behind the label.

Markdown
"use client";

import { FillSweepButton } from "@/siteplane/components/animated-buttons";

export default function Example() {
  return <FillSweepButton>Continue</FillSweepButton>;
}

Installation

pnpm dlx shadcn@4.18.0 add @siteplane/animated-buttons

Complete the one-time setup first. Registry JSON lists source files and dependencies.

Usage

import { FillSweepButton } from "@/siteplane/components/animated-buttons";

<FillSweepButton>Continue</FillSweepButton>;

Fill variants

FillSweepButton keeps Button behavior and sweeps a fill in on hover. destructive uses the outlined destructive surface.

"use client";

import { FillSweepButton } from "@/siteplane/components/animated-buttons";

export default function Example() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      {(["default", "destructive", "inverse", "outline"] as const).map(
        (variant) => (
          <FillSweepButton key={variant} variant={variant}>
            {variant}
          </FillSweepButton>
        ),
      )}
    </div>
  );
}

Expanding actions

ExpandingArrowButton expands its arrow circle behind the label on hover and can render a link. ExpandingLogoutButton shows its icon and reveals label on hover and keyboard focus; label is also its accessible name.

"use client";

import {
  ExpandingArrowButton,
  ExpandingLogoutButton,
} from "@/siteplane/components/animated-buttons";

export default function Example() {
  return (
    <div className="flex flex-wrap items-center gap-4">
      <ExpandingArrowButton
        label="View projects"
        render={<a href="#projects" />}
      />
      <ExpandingLogoutButton />
    </div>
  );
}

Sizes and states

The expanding recipes accept sm, md, lg, and xl. Disabled and loading buttons don't animate.

"use client";

import {
  ExpandingArrowButton,
  FillSweepButton,
} from "@/siteplane/components/animated-buttons";

const sizes = [
  { size: "sm", label: "Small" },
  { size: "md", label: "Medium" },
  { size: "lg", label: "Large" },
  { size: "xl", label: "Extra large" },
] as const;

export default function Example() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      {sizes.map(({ size, label }) => (
        <ExpandingArrowButton key={size} size={size} label={label} />
      ))}
      <FillSweepButton disabled>Continue</FillSweepButton>
      <FillSweepButton loading>Saving</FillSweepButton>
    </div>
  );
}

API reference

Component properties
PropTypeDefaultDescription
FillSweepButton.variantdefault | destructive | inverse | outlinedefaultButton surface; destructive renders the outlined destructive surface.
FillSweepButton.childrenReactNodeunsetVisible content.
ExpandingArrowButton.labelReactNodeLearn moreLabel; replaces children.
ExpandingArrowButton.varianttext | defaulttextSurface; default sets the arrow on the default Button's fill, hairline rim and depth.
ExpandingLogoutButton.labelstringLog outLabel and default accessible name.
ExpandingLogoutButton.variantdefault | destructive | inverse | outlinedestructiveButton surface; destructive renders the outlined destructive surface.
Arrow / Logout.sizesm | md | lg | xlprovider / lgControl size; follows SiteplaneUIProvider when omitted.
Arrow / Logout.typebutton | submit | resetbuttonNative button type; not set when render supplies a link.
ExpandingLogoutButton.aria-labelstringlabelAccessible name override.

FillSweepButtonProps extends ButtonBaseProps except variant and accepts every Button size. ExpandingArrowButtonProps and ExpandingLogoutButtonProps omit children, size, and variant and add label, the control size and their own variant subset. The three Props types are exported; AnimatedButtonVariant is not. onClick, disabled, loading, render, style, and refs follow Button.

Read the installed source.

Usage notes

Keep actions understandable without motion. Reduced-motion behavior belongs to the built-in styles. Use actual links for navigation; leave space for expanding labels and avoid clipping them in narrow parents.