bash
npx logic2b@latest add code-blockimport { CodeBlock } from "@/components/ui/code-block"
export default function CodeBlockDemo() {
return (
<CodeBlock
language="bash"
code="npx logic2b@latest add code-block"
className="w-full max-w-md"
/>
)
}Installation
npx logic2b@latest add code-blockWorking with an AI assistant? Copy this prompt into Claude Code, Cursor or Copilot — it carries the install steps, a no-CLI fallback and a verification checklist.
Add the "code-block" item from the logic2b ui registry (https://ui.logic2b.com) to this project. Follow every step and verify at the end. ## Steps 1. If the project has no `components.json` yet, set up logic2b ui first: ```bash npx logic2b@latest init ``` 2. Install the item (the CLI resolves registry dependencies automatically): ```bash npx logic2b@latest add code-block ``` 3. Install any npm dependencies the command prints. ## If the CLI is not available Do it manually from the registry payload: 1. Fetch https://ui.logic2b.com/r/code-block.json. 2. Write every entry in `files[]` to its mapped project path (see below). 3. Repeat (recursively) for each name in `registryDependencies`. 4. Install every package listed in `dependencies` across those payloads. ## Registry reference - Index of every item: https://ui.logic2b.com/r/index.json - Item payload (full source): https://ui.logic2b.com/r/<name>.json - Usage examples per item: https://ui.logic2b.com/r/demos/index.json → https://ui.logic2b.com/r/demos/<demo>.json - Docs index for agents: https://ui.logic2b.com/llms.txt (full docs: https://ui.logic2b.com/llms-full.txt) - Every docs page is Markdown when you append `.md` to its URL. Registry file paths map to project paths like this: - `ui/*` → `@/components/ui/*` - `blocks/<name>/*` → `@/components/*` - `charts/*` → `@/components/charts/*` - `hooks/*` → `@/hooks/*` - `lib/utils.ts` → `@/lib/utils.ts` - `theme.css` → next to the project's Tailwind entry stylesheet ## Conventions (do not break these) - Tailwind CSS v4 (CSS-first config; no tailwind.config.js needed) and React 19. - All colors go through semantic tokens (`bg-primary`, `text-muted-foreground`, `border-border`, …). Never hardcode hex/oklch values in components. - Dark mode is class-based: toggle `.dark` on `<html>`. - Icons come from lucide-react. ## Verify before finishing 1. The dev server starts and the app renders without console errors. 2. TypeScript compiles (`tsc --noEmit` or the framework's check). 3. Components use the theme: a `<Button>` shows the primary token color, and toggling `.dark` on `<html>` switches the palette.
Install the dependencies:
npm install lucide-reactCopy into ui/code-block.tsx:
"use client"
import * as React from "react"
import { CheckIcon, CopyIcon } from "lucide-react"
import { cn } from "@/lib/utils"
export interface CodeBlockProps
extends Omit<React.ComponentProps<"div">, "children"> {
/** The code to render and copy. */
code: string
/** Optional language label shown in the header (display only — no highlighting). */
language?: string
}
/**
* A styled code container with a one-click copy button. Dependency-free (no
* syntax highlighter): renders the code verbatim in a `<pre>` and copies it via
* the Clipboard API, with a copied-state affordance.
*/
function CodeBlock({ className, code, language, ...props }: CodeBlockProps) {
const [copied, setCopied] = React.useState(false)
const timer = React.useRef<ReturnType<typeof setTimeout> | undefined>(
undefined
)
React.useEffect(() => () => clearTimeout(timer.current), [])
const copy = async () => {
try {
await navigator.clipboard.writeText(code)
setCopied(true)
clearTimeout(timer.current)
timer.current = setTimeout(() => setCopied(false), 2000)
} catch {
// Clipboard unavailable (insecure context / denied) — no-op.
}
}
const CopyButton = (
<button
type="button"
onClick={copy}
aria-label={copied ? "Copied" : "Copy code"}
className={cn(
"text-muted-foreground hover:bg-accent hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors outline-none",
"focus-visible:ring-ring/50 focus-visible:ring-[3px]"
)}
>
{copied ? (
<CheckIcon className="size-3.5" />
) : (
<CopyIcon className="size-3.5" />
)}
</button>
)
return (
<div
data-slot="code-block"
className={cn(
"bg-muted/40 relative overflow-hidden rounded-lg border",
className
)}
{...props}
>
{language ? (
<div className="flex items-center justify-between border-b px-3 py-1.5">
<span className="text-muted-foreground font-mono text-xs">
{language}
</span>
{CopyButton}
</div>
) : (
<div className="absolute top-1.5 right-1.5 z-10">{CopyButton}</div>
)}
<pre
className={cn(
"overflow-x-auto p-4 text-sm leading-relaxed",
!language && "pr-11"
)}
>
<code className="font-mono">{code}</code>
</pre>
</div>
)
}
export { CodeBlock }Usage
import { CodeBlock } from "@/components/ui/code-block"
<CodeBlock language="tsx" code={`const answer = 42`} />
The copy button writes code to the clipboard and shows a checkmark for two
seconds. Omit language to render a bare block with a floating copy button in
the corner.
Highlighting
CodeBlock is deliberately dependency-free and does not ship a syntax
highlighter. To add highlighting, render your highlighter’s output inside the
<pre> — e.g. pass Shiki/Prism-generated HTML — or wrap this component. Keeping
the base free of a highlighter means it stays tiny and framework-agnostic.
API
| Prop | Type | Default |
|---|---|---|
code |
string |
— (required) |
language |
string (display label) |
— |
| …props | React.ComponentProps<"div"> |
— |