Component Preview
A Preview / Code tabbed container for showcasing live components next to their source.
Preview
1 function InstallDropdown({ slug }: { slug: string }) {2const [open, setOpen] = useState(false);3const [selected, setSelected] = useState<PackageManager>("npx");4const [copied, setCopied] = useState(false);5const ref = useRef<HTMLDivElement>(null);6 7useEffect(() => {8 function handleOutside(e: MouseEvent) {9 if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);10 }11 document.addEventListener("mousedown", handleOutside);12 return () => document.removeEventListener("mousedown", handleOutside);13}, []);14 15const command = packageCommands[selected](slug);16 17const handleCopy = async () => {18 if (copied) return;19 try {20 if (navigator.clipboard && window.isSecureContext) {21 await navigator.clipboard.writeText(command);22 } else {23 const el = document.createElement("textarea");24 el.value = command;25 el.style.cssText = "position:absolute;left:-9999px;top:-9999px";26 document.body.appendChild(el);27 el.focus();28 el.select();29 document.execCommand("copy");30 document.body.removeChild(el);31 }32 setCopied(true);33 setTimeout(() => setCopied(false), 3000);34 } catch (err) {35 console.error("Copy failed:", err);36 }37};1 function InstallDropdown({ slug }: { slug: string }) {2const [open, setOpen] = useState(false);3const [selected, setSelected] = useState<PackageManager>("npx");4const [copied, setCopied] = useState(false);5const ref = useRef<HTMLDivElement>(null);6 7useEffect(() => {8 function handleOutside(e: MouseEvent) {9 if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);10 }11 document.addEventListener("mousedown", handleOutside);12 return () => document.removeEventListener("mousedown", handleOutside);13}, []);14 15const command = packageCommands[selected](slug);16 17const handleCopy = async () => {18 if (copied) return;19 try {20 if (navigator.clipboard && window.isSecureContext) {21 await navigator.clipboard.writeText(command);22 } else {23 const el = document.createElement("textarea");24 el.value = command;25 el.style.cssText = "position:absolute;left:-9999px;top:-9999px";26 document.body.appendChild(el);27 el.focus();28 el.select();29 document.execCommand("copy");30 document.body.removeChild(el);31 }32 setCopied(true);33 setTimeout(() => setCopied(false), 3000);34 } catch (err) {35 console.error("Copy failed:", err);36 }37};Installation
- 1
Run the following command
npx shadcn@latest add https://localhostui.com/r/code-preview-block.json
Props
| Prop | Type | Default | Description |
|---|---|---|---|
link* | string | — | Identifies this preview and derives the install slug (last path segment) used for CLI/AI-prompt commands and the iframe preview URL. |
children | React.ReactNode | — | The live component to render in the Preview tab. Omit for a code-only entry — shows a fallback message instead of an empty panel. |
code | string | — | Source code shown in the Code tab, syntax-highlighted via Shiki. Omit to show a "no code provided" message instead. |
language | string | "tsx" | Shiki language id used to highlight `code`. |
className | string | — | Extra classes applied to the inner white/black panel (border, radius, background). |
frameClassName | string | "bg-neutral-100 dark:bg-neutral-900" | Classes for the outer padded frame behind the panel — the "outer-layer" background color. |
useIframe | boolean | — | Renders the Preview tab as an iframe pointed at `{prePath}/preview/{link}` instead of rendering `children` directly. |
compact | boolean | — | Reduces the Preview tab's minimum height from 500px to 120px. Ignored when `isBlock` is true. |