Animated CTA Buttons Hold Action Button
beui/hold-action-buttonFreeComponent
Hold to complete with a vertical or horizontal liquid fill; release early to cancel.
Install it
npx shadcn@latest add https://beui.dev/r/hold-action-button.jsonSource
1"use client";2// beui.dev/components/motion/expanding-arrow-button34import { motion, useReducedMotion, type HTMLMotionProps } from "motion/react";5import {6 forwardRef,7 useRef,8 useState,9 type KeyboardEvent,10 type PointerEvent,11 type ReactNode,12} from "react";13import { EASE_OUT, SPRING_PRESS } from "@/lib/ease";14import { cn } from "@/lib/utils";1516export interface HoldActionButtonProps extends Omit<17 HTMLMotionProps<"button">,18 | "children"19 | "type"20 | "onClick"21 | "onPointerDown"22 | "onPointerUp"23 | "onPointerCancel"24 | "onPointerLeave"25 | "onKeyDown"26 | "onKeyUp"27> {28 children: ReactNode;29 type?: "vertical" | "horizontal";30 holdingLabel?: ReactNode;31 completeLabel?: ReactNode;32 holdDuration?: number;33 onHoldComplete?: () => void;34 fillClassName?: string;35 labelClassName?: string;36}3738export const HoldActionButton = forwardRef<39 HTMLButtonElement,40 HoldActionButtonProps41>(function HoldActionButton(42 {43 children,44 type = "vertical",45 holdingLabel = "Keep holding",46 completeLabel = "Done",47 holdDuration = 1600,48 onHoldComplete,49 fillClassName,50 labelClassName,51 className,52 disabled,53 ...rest54 },55 ref,56) {57 const reduce = useReducedMotion();58 const completedRef = useRef(false);59 const [holding, setHolding] = useState(false);60 const [completed, setCompleted] = useState(false);6162 const startHold = () => {63 if (disabled || holding) return;64 completedRef.current = false;65 setCompleted(false);66 setHolding(true);67 };6869 const cancelHold = () => {70 setHolding(false);71 setCompleted(false);72 };7374 const handlePointerDown = (event: PointerEvent<HTMLButtonElement>) => {75 if (event.button !== 0) return;76 event.currentTarget.setPointerCapture(event.pointerId);77 startHold();78 };7980 const handlePointerUp = (event: PointerEvent<HTMLButtonElement>) => {81 if (event.currentTarget.hasPointerCapture(event.pointerId)) {82 event.currentTarget.releasePointerCapture(event.pointerId);83 }84 cancelHold();85 };8687 const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {88 if ((event.key === " " || event.key === "Enter") && !event.repeat) {89 event.preventDefault();90 startHold();91 }92 };9394 const handleKeyUp = (event: KeyboardEvent<HTMLButtonElement>) => {95 if (event.key === " " || event.key === "Enter") {96 event.preventDefault();97 cancelHold();98 }99 };100101 const handleFillComplete = () => {102// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Action Swap Bluraction-swap-blur | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Cascadeaction-swap-cascade | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Rollaction-swap-roll | beui | Components | Free | 3 deps · 4 files | |
| Agent Activityagent-activity | beui | Components | Free | 4 deps · 9 files | |
| Agent Loading States Agent Progressagent-progress | beui | Components | Free | 3 deps · 3 files | |
| AI Sidebarai-sidebar | beui | Components | Free | 4 deps · 5 files | |
| Animated Badgeanimated-badge | beui | Components | Free | 4 deps · 3 files | |
| Number Animation Animated Numberanimated-number | beui | Components | Free | 3 deps · 3 files |
