Slide to Unlock
A sleek, interactive slider inspired by the classic iPhone OS "slide to unlock" gesture.
Loading...
"use client";
import { toast } from "sonner";
import { useSound } from "@/hooks/use-sound";
import { ShimmeringText } from "@/components/ncdai/shimmering-text";
import {
SlideToUnlock,
SlideToUnlockHandle,
SlideToUnlockText,
SlideToUnlockTrack,
} from "@/components/ncdai/slide-to-unlock";
export function SlideToUnlockDemo1() {
const playSound = useSound("/audio/ui-sounds/unlock.wav");
return (
<SlideToUnlock
onUnlock={() => {
playSound();
toast.success("Unlocked");
}}
>
<SlideToUnlockTrack>
<SlideToUnlockText>
{({ isDragging }) => (
<ShimmeringText text="slide to unlock" isStopped={isDragging} />
)}
</SlideToUnlockText>
<SlideToUnlockHandle />
</SlideToUnlockTrack>
</SlideToUnlock>
);
}"awesome. Love the components, especially slide-to-unlock. Great job"
— Guillermo Rauch, CEO & Founder at Vercel
Installation
pnpm dlx shadcn add @ncdai/slide-to-unlock
Usage
import {
SlideToUnlock,
SlideToUnlockHandle,
SlideToUnlockText,
SlideToUnlockTrack,
} from "@/components/ncdai/slide-to-unlock";
import { ShimmeringText } from "@/component/ncdai/shimmering-text";<SlideToUnlock>
<SlideToUnlockTrack>
<SlideToUnlockText>
<ShimmeringText />
</SlideToUnlockText>
<SlideToUnlockHandle />
</SlideToUnlockTrack>
</SlideToUnlock>API Reference
SlideToUnlock
The root component that provides context for all child components.
| Prop | Type | Default | Description |
|---|---|---|---|
handleWidth | number | 56 | Width of the draggable handle in pixels. |
onUnlock | () => void | Callback function triggered when the handle reaches the end. | |
className | string | Additional CSS classes to apply to the root element. |
SlideToUnlockTrack
The container that holds the text and handle components.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes to apply to the track element. |
SlideToUnlockText
The text label that fades out as the handle is dragged.
| Prop | Type | Description |
|---|---|---|
children | ReactNode | (props: { isDragging: boolean }) => ReactNode | Text content or render function that receives dragging state. |
className | string | Additional CSS classes to apply to the text element. |
SlideToUnlockHandle
The draggable handle element.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | ArrowRight | Custom icon or content to display inside the handle. |
className | string | Additional CSS classes to apply to the handle element. |
ShimmeringText
An animated text component that creates a shimmering effect by sequentially animating each character's color.
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | The text content to display with the shimmering effect. | |
duration | number | 1 | The duration (in seconds) for each character's shimmer animation cycle. |
isStopped | boolean | false | Controls whether the animation is stopped. When true, characters return to their base color. |
className | string | Additional CSS classes to apply to the root span element. |
Examples
Default
Loading...
"use client";
import { toast } from "sonner";
import { useSound } from "@/hooks/use-sound";
import { ShimmeringText } from "@/components/ncdai/shimmering-text";
import {
SlideToUnlock,
SlideToUnlockHandle,
SlideToUnlockText,
SlideToUnlockTrack,
} from "@/components/ncdai/slide-to-unlock";
export function SlideToUnlockDemo1() {
const playSound = useSound("/audio/ui-sounds/unlock.wav");
return (
<SlideToUnlock
onUnlock={() => {
playSound();
toast.success("Unlocked");
}}
>
<SlideToUnlockTrack>
<SlideToUnlockText>
{({ isDragging }) => (
<ShimmeringText text="slide to unlock" isStopped={isDragging} />
)}
</SlideToUnlockText>
<SlideToUnlockHandle />
</SlideToUnlockTrack>
</SlideToUnlock>
);
}Custom Color
Loading...
"use client";
import { toast } from "sonner";
import { ShimmeringText } from "@/components/ncdai/shimmering-text";
import {
SlideToUnlock,
SlideToUnlockHandle,
SlideToUnlockText,
SlideToUnlockTrack,
} from "@/components/ncdai/slide-to-unlock";
export function SlideToUnlockDemo2() {
return (
<>
<SlideToUnlock
className="bg-linear-to-b from-zinc-800 to-zinc-900"
onUnlock={() => {
const myPromise = new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, 1000);
});
toast.promise(myPromise, {
loading: "Connecting...",
success: () => `Connected`,
error: ({ message }) => `Error: ${message}`,
});
}}
>
<SlideToUnlockTrack>
<SlideToUnlockText>
{({ isDragging }) => (
<ShimmeringText
className="[--color:var(--color-zinc-600)] [--shimmering-color:var(--color-zinc-50)]"
text="slide to answer"
isStopped={isDragging}
/>
)}
</SlideToUnlockText>
<SlideToUnlockHandle className="bg-linear-to-b from-emerald-500 to-emerald-700 text-white" />
</SlideToUnlockTrack>
</SlideToUnlock>
</>
);
}Custom Handle
Loading...
"use client";
import { toast } from "sonner";
import { ShimmeringText } from "@/components/ncdai/shimmering-text";
import {
SlideToUnlock,
SlideToUnlockHandle,
SlideToUnlockText,
SlideToUnlockTrack,
} from "@/components/ncdai/slide-to-unlock";
export function SlideToUnlockDemo3() {
return (
<SlideToUnlock
className="w-[180px] rounded-full ring-0"
handleWidth={40}
onUnlock={() => toast.success("Stopped")}
>
<SlideToUnlockTrack>
<SlideToUnlockText className="pl-0">
{({ isDragging }) => (
<ShimmeringText text="slide to stop" isStopped={isDragging} />
)}
</SlideToUnlockText>
<SlideToUnlockHandle className="w-10 rounded-full dark:bg-zinc-700">
<svg
className="size-5 dark:text-white"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
>
<path
d="M216,56V200a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V56A16,16,0,0,1,56,40H200A16,16,0,0,1,216,56Z"
fill="currentColor"
/>
</svg>
</SlideToUnlockHandle>
</SlideToUnlockTrack>
</SlideToUnlock>
);
}