Components
Loading preview...
Minimal, theme-aware preview that opens with Space, navigates with Arrow keys, and closes with Esc—instant content without leaving context.
@jatin-yadav05
npx shadcn@latest add https://21st.dev/r/jatin-yadav05/quick-look-overlayimport { QuickLookOverlay, PreviewGrid, type PreviewItem } from "@/components/ui/quick-look-overlay";
import { useMemo, useState } from "react"
export default function Page() {
const items: PreviewItem[] = useMemo(
() => [
{
id: "img-1",
title: "Alpine Morning",
kind: "image",
src: "https://images.pexels.com/photos/34020255/pexels-photo-34020255.jpeg",
},
{
id: "img-2",
title: "Workspace",
kind: "image",
src: "https://images.pexels.com/photos/4065876/pexels-photo-4065876.jpeg",
},
{
id: "img-3",
title: "City Sunset",
kind: "image",
src: "https://images.pexels.com/photos/34032149/pexels-photo-34032149.jpeg",
},
{
id: "code-1",
title: "Button.tsx",
kind: "code",
content: `import { cn } from "@/lib/utils"
export function Button({ className, ...props }) {
return (
<button
className={cn(
"inline-flex items-center justify-center rounded-md border border-border bg-primary px-3 py-1.5 text-primary-foreground hover:bg-primary/90",
"focus:outline-none focus:ring-2 focus:ring-ring",
className
)}
{...props}
/>
)
}`,
},
{
id: "img-4",
title: "Forest Path",
kind: "image",
src: "https://images.pexels.com/photos/213172/pexels-photo-213172.jpeg",
},
{
id: "img-5",
title: "Coastal Blue",
kind: "image",
src: "https://images.pexels.com/photos/34033513/pexels-photo-34033513.jpeg",
},
{
id: "text-1",
title: "Product Note",
kind: "text",
content:
"Quick Look is a zero-friction preview: press Space to peek, Esc to dismiss, and arrows to cycle—no heavy UI, just the content.",
},
{
id: "img-6",
title: "Architectural Lines",
kind: "image",
src: "https://images.pexels.com/photos/3605420/pexels-photo-3605420.jpeg",
},
],
[],
)
const [open, setOpen] = useState(false)
const [current, setCurrent] = useState(0)
const openAt = (i: number) => {
setCurrent(i)
setOpen(true)
}
const onPrev = () => {
setCurrent((i) => (i - 1 + items.length) % items.length)
}
const onNext = () => {
setCurrent((i) => (i + 1) % items.length)
}
return (
<main className="mx-auto max-w-6xl px-4 py-10">
<header className="mb-8">
<h1 className="text-balance text-2xl font-semibold">Quick Look</h1>
<p className="mt-2 text-sm text-muted-foreground">
Focus an item and press Space to preview. Use ← → to navigate, Esc to close.
</p>
</header>
<PreviewGrid items={items} onOpen={openAt} />
<QuickLookOverlay
open={open}
item={items[current] ?? null}
index={current}
total={items.length}
onClose={() => setOpen(false)}
onPrev={onPrev}
onNext={onNext}
/>
</main>
)
}