Move To Top
refinery/move-to-top-buttonFreeComponent
Direction aware scroll progress button that helps to jump top or bottom on click.
Live preview
live · rendered by the registry
Rendered by refinery on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://refinery.abhii.me/r/move-to-top-button.jsonSource
1"use client";23import {4 motion,5 AnimatePresence,6 useScroll,7 useMotionValueEvent,8 useTransform,9} from "motion/react";10import { useRef, useState } from "react";11import { cn } from "../lib/utils";1213type Mode = "down" | "up";1415interface MoveToTopProps {16 className?: string;17 size?: number;18}1920export default function MoveToTop({ className, size = 44 }: MoveToTopProps) {21 const [iconMode, setIconMode] = useState<Mode>("down");2223 const { scrollY, scrollYProgress } = useScroll();2425 const lastY = useRef(0);26 const directionRef = useRef<Mode>("down");2728 useMotionValueEvent(scrollY, "change", (y) => {29 if (y > lastY.current + 4) {30 directionRef.current = "down";31 } else if (y < lastY.current - 4) {32 directionRef.current = "up";33 }3435 lastY.current = y;36 });3738 useMotionValueEvent(scrollYProgress, "change", (p) => {39 const next: Mode =40 p <= 0.01 ? "down" : p >= 0.99 ? "up" : directionRef.current;4142 setIconMode((prev) => (prev === next ? prev : next));43 });4445 const r = (size - 4) / 2;46 const cx = size / 2;47 const cy = size / 2;48 const circumference = 2 * Math.PI * r;49 const dashoffset = useTransform(50 scrollYProgress,51 (p) => circumference * (1 - p)52 );5354 const handleClick = () => {55 if (iconMode === "down") {56 window.scrollTo({57 top: document.documentElement.scrollHeight,58 behavior: "smooth",59 });60 return;61 }62 window.scrollTo({ top: 0, behavior: "smooth" });63 };6465 return (66 <button67 aria-label={iconMode === "down" ? "Scroll to bottom" : "Scroll to top"}68 onClick={handleClick}69 className={cn("fixed right-6 bottom-6 z-50 rounded-full", className)}70 >71 <div72 style={{ width: size, height: size }}73 className="relative rounded-full bg-neutral-900 text-white shadow-lg shadow-black/30"74 >75 <svg76 width={size}77 height={size}78 viewBox={`0 0 ${size} ${size}`}79 className="absolute inset-0"80 >81 <circle82 cx={cx}83 cy={cy}84 r={r}85 fill="transparent"86 strokeWidth={4}87 className="stroke-white/20"88 />8990 <motion.circle91 cx={cx}92 cy={cy}93 r={r}94 fill="transparent"95 strokeWidth={4}96 stroke="currentColor"97 strokeLinecap="round"98 strokeDasharray={circumference}99 strokeDashoffset={dashoffset}100// … truncated
What it pulls in
npm packages
Files it writes
More from refinery
All 16 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analog Clock Screensaveranalog-clock-screensaver | refinery | Components | Free | 1 dep | |
| Avatar Circleavatar-circle | refinery | Components | Free | 1 dep | |
| DVD Screensaverdvd-screensaver | refinery | Components | Free | 1 dep | |
| Floating Cardfloating-card | refinery | Components | Free | 1 dep | |
| Floating Navfloating-nav | refinery | Components | Free | 1 dep | |
| Glowy Buttonglowy-button | refinery | Components | Free | 1 dep | |
| Notification Badgenotification-badge | refinery | Components | Free | 1 dep | |
| Sleeping Cat Screensaversleeping-cat-screensaver | refinery | Components | Free | 2 deps |
