Code Block
Displays syntax-highlighted code with an optional header for language, title, and actions.
'use client'
import { CodeBlock } from '@nerdfish/react/code-block'
const code = `function greet(name: string) {
return \`Hello, \${name}!\`
}
greet('world')`
export default function CodeBlockExample() {
return <CodeBlock code={code} language="typescript" />
}
With Header
Pass title and/or language to show a header with a copy button.
'use client'
import { CodeBlock } from '@nerdfish/react/code-block'
const code = `import { useState } from 'react'
export default function useCounter(initial = 0) {
const [count, setCount] = useState(initial)
return {
count,
increment: () => setCount((value) => value + 1),
decrement: () => setCount((value) => value - 1),
}
}`
export default function CodeBlockWithHeaderExample() {
return <CodeBlock title="useCounter.ts" language="typescript" code={code} />
}
Custom Copy Button
Use the actions prop to replace the default icon-only copy button.
'use client'
import { Button } from '@nerdfish/react/button'
import { CodeBlock } from '@nerdfish/react/code-block'
import { useCopyToClipboard } from '@nerdfish/react/hooks/use-copy-to-clipboard'
import { CheckIcon, CopyIcon } from 'lucide-react'
const codeText = `export async function fetchUser(id: string) {
const response = await fetch(\`/api/users/\${id}\`)
if (!response.ok) {
throw new Error('Failed to fetch user')
}
return response.json()
}`
function CustomCopyAction({ code }: { code: string }) {
const { handleCopy, copiedText } = useCopyToClipboard()
return (
<Button
size="xs"
variant={copiedText ? 'success' : 'outline'}
onClick={() => void handleCopy(code, 3000)}
>
{copiedText ? (
<CheckIcon className="size-4" />
) : (
<CopyIcon className="size-4" />
)}
{copiedText ? 'Copied' : 'Copy code'}
</Button>
)
}
export default function CodeBlockCustomCopyExample() {
return (
<CodeBlock
title="api.ts"
language="typescript"
code={codeText}
actions={<CustomCopyAction code={codeText} />}
/>
)
}