ComponentsPower Off Slide
Power Off Slide
Inspired by the power off animation of iPhones, this component allows the user to slide to power off the device.
Slide to power off
Code
Install with shadcn Beta
Terminal
npx shadcn@latest add "https://smoothui.dev/r/power-off-slide.json"
Manual install
Terminal
npm install motion lucide-react
PowerOffSlide.tsx
"use client"
import { RefObject, useRef, useState } from "react"
import { Power } from "lucide-react"
import {
motion,
useAnimation,
useAnimationFrame,
useMotionValue,
useTransform,
} from "motion/react"
export default function PowerOffSlide() {
const [isPoweringOff, setIsPoweringOff] = useState(false)
const x = useMotionValue(0)
const controls = useAnimation()
const constraintsRef = useRef(null)
const textRef: RefObject<HTMLDivElement | null> = useRef(null)
const xInput = [0, 164]
const opacityOutput = [0, 1]
const opacity = useTransform(x, xInput, opacityOutput)
useAnimationFrame((t) => {
const duration = 2000
const progress = (t % duration) / duration
if (textRef.current) {
textRef.current.style.setProperty("--x", `${(1 - progress) * 100}%`)
}
})
const handleDragEnd = async () => {
const dragDistance = x.get()
if (dragDistance > 160) {
await controls.start({ x: 168 })
setIsPoweringOff(true)
// Add a timeout to reset the component after 2 seconds
setTimeout(() => {
setIsPoweringOff(false)
controls.start({ x: 0 })
x.set(0)
}, 2000)
} else {
controls.start({ x: 0 })
}
}
return (
<div className="flex h-auto items-center justify-center">
<div className="w-56">
{isPoweringOff ? (
<div className="text-light-950 dark:text-dark-950 text-center">
<p className="mb-2 text-xl font-light">Shutting down...</p>
</div>
) : (
<div
ref={constraintsRef}
className="bg-light-400 dark:bg-dark-400 relative h-14 overflow-hidden rounded-full"
>
<div className="absolute inset-0 left-8 z-0 flex items-center justify-center overflow-hidden">
<div className="text-md loading-shimmer text-light-950 relative w-full text-center font-normal select-none">
Slide to power off
</div>
</div>
<motion.div
drag="x"
dragConstraints={{ left: 0, right: 168 }}
dragElastic={0}
dragMomentum={false}
onDragEnd={handleDragEnd}
animate={controls}
style={{ x }}
className="bg-light-50 dark:bg-dark-50 absolute top-1 left-1 z-10 flex h-12 w-12 cursor-grab items-center justify-center rounded-full shadow-md active:cursor-grabbing"
>
<Power size={32} className="text-red-600" />
</motion.div>
</div>
)}
</div>
</div>
)
}