Patterns
Code Block
A code sample or a command in the monospace font, with a copy button.
Patterns
A code sample or a command in the monospace font, with a copy button.
Add the package
$ npm install @acme/sdkCreate an invoice
import { Acme } from '@acme/sdk'
const acme = new Acme(process.env.ACME_API_KEY)
await acme.invoices.create({ customer: 'cus_4QbX2', amount: 4280 })import { Card, CardContent, CardDescription, CardHeader, CardTitle, CodeBlock } from 'ferry-ui'
const SAMPLE = `import { Acme } from '@acme/sdk'
const acme = new Acme(process.env.ACME_API_KEY)
await acme.invoices.create({ customer: 'cus_4QbX2', amount: 4280 })`
export default function CodeBlockHero() {
return (
<Card className="w-full max-w-lg">
<CardHeader>
<div>
<CardTitle>Install the SDK</CardTitle>
<CardDescription>Send your first request to the Invoices API.</CardDescription>
</div>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<div className="flex flex-col gap-1.5">
<p className="text-[13px] font-medium text-foreground">Add the package</p>
<CodeBlock prompt code="npm install @acme/sdk" />
</div>
<div className="flex flex-col gap-1.5">
<p className="text-[13px] font-medium text-foreground">Create an invoice</p>
<CodeBlock what="code sample" code={SAMPLE} />
</div>
</CardContent>
</Card>
)
}CopyField. For a secret that the user can show, use SecretField. See Copy.mono.Import the parts. Give plain text to code. For content with elements, use the children and copyValue.
import { CodeBlock, CodeBlockPrompt } from 'ferry-ui'
<CodeBlock code="" />
<CodeBlock copyValue="">
<CodeBlockPrompt />
</CodeBlock>The variant prop sets the look.
| Variant | Look | Use |
|---|---|---|
block (default) | A box with a border. | Commands and code samples. |
inline | A compact chip of one line. | A short token in a list or in help text. |
terminal | A decorative window. | An illustration in an empty state. |
prompt shows a $ before each line of code that is not empty. The copy button does not copy the prompt. Pass a string to show a different prompt.
$ npx acme login$ git clone https://example.com/acme/web-app.git $ cd web-app $ npm install $ npm run dev
sql> SELECT id, total FROM invoices;import { CodeBlock } from 'ferry-ui'
const SETUP = `git clone https://example.com/acme/web-app.git
cd web-app
npm install
npm run dev`
export default function CodeBlockPromptProp() {
return (
<div className="flex w-full max-w-md flex-col gap-3">
<CodeBlock prompt code="npx acme login" />
<CodeBlock prompt code={SETUP} what="setup commands" />
<CodeBlock prompt="sql>" code="SELECT id, total FROM invoices;" what="query" />
</div>
)
}copyValue sets the text that the button copies. Use it to show a masked key and to copy the real key.
$ export ACME_API_KEY=sk_demo_••••3f6aimport { CodeBlock } from 'ferry-ui'
export default function CodeBlockMasked() {
return (
<CodeBlock
className="max-w-md"
prompt
code="export ACME_API_KEY=sk_demo_••••3f6a"
copyValue="export ACME_API_KEY=sk_demo_4f9a2c7e1b8d3f6a"
what="command with your API key"
/>
)
}A long line scrolls in the block. copyPlacement="side" puts the copy button in its own column. wrap breaks the long lines.
curl -X POST https://api.example.com/v2/invoices -H "Authorization: Bearer $ACME_API_KEY" -d customer=cus_4QbX2
curl -X POST https://api.example.com/v2/invoices -H "Authorization: Bearer $ACME_API_KEY" -d customer=cus_4QbX2
curl -X POST https://api.example.com/v2/invoices -H "Authorization: Bearer $ACME_API_KEY" -d customer=cus_4QbX2
import { CodeBlock } from 'ferry-ui'
const REQUEST =
'curl -X POST https://api.example.com/v2/invoices -H "Authorization: Bearer $ACME_API_KEY" -d customer=cus_4QbX2'
export default function CodeBlockLongLines() {
return (
<div className="flex w-full max-w-sm flex-col gap-3">
<CodeBlock code={REQUEST} what="request" />
<CodeBlock code={REQUEST} what="request" copyPlacement="side" />
<CodeBlock code={REQUEST} what="request" wrap />
</div>
)
}The inline variant is a chip of one line. Use it for a short token in a list or in help text.
{{customer.first_name}}The first name of the customer.
{{invoice.total}}The total of the invoice, with its currency.
{{workspace.portal_url}}The link to the billing portal of the workspace.
import { CodeBlock } from 'ferry-ui'
const PLACEHOLDERS = [
{ code: '{{customer.first_name}}', help: 'The first name of the customer.' },
{ code: '{{invoice.total}}', help: 'The total of the invoice, with its currency.' },
{ code: '{{workspace.portal_url}}', help: 'The link to the billing portal of the workspace.' },
]
export default function CodeBlockInline() {
return (
<div className="w-full max-w-sm divide-y rounded-lg border">
{PLACEHOLDERS.map((placeholder) => (
<div key={placeholder.code} className="flex flex-col gap-1.5 px-4 py-3">
<CodeBlock variant="inline" code={placeholder.code} what="placeholder" />
<p className="text-[13px] text-foreground-light">{placeholder.help}</p>
</div>
))}
</div>
)
}The terminal variant is decorative. It has no copy button unless you set copyable. If it repeats the text near it, add aria-hidden.
$ npm run test ✓ invoices.test.ts (12 tests) ✓ customers.test.ts (8 tests) ! 1 snapshot is obsolete
import { CodeBlock, CodeBlockPrompt } from 'ferry-ui'
export default function CodeBlockTerminal() {
return (
<CodeBlock variant="terminal" className="w-full max-w-md">
<CodeBlockPrompt />
npm run test
{'\n'}
<span className="text-success">✓ invoices.test.ts (12 tests)</span>
{'\n'}
<span className="text-success">✓ customers.test.ts (8 tests)</span>
{'\n'}
<span className="text-warning">! 1 snapshot is obsolete</span>
</CodeBlock>
)
}The children replace code. Use them to give a color to a part of the text. CodeBlockPrompt adds the prompt. The copy button shows only if you pass copyValue.
$ acme invoices list --status overdue
import { CodeBlock, CodeBlockPrompt } from 'ferry-ui'
export default function CodeBlockRich() {
return (
<CodeBlock className="max-w-md" copyValue="acme invoices list --status overdue" what="command">
<CodeBlockPrompt />
acme invoices list <span className="text-primary">--status</span> overdue
</CodeBlock>
)
}copyable={false} hides the copy button. Use it for a read-only sample that the user must not paste as it is.
Invoice INV-2041 has the status "paid". Amount: $4,280.00
import { CodeBlock } from 'ferry-ui'
const OUTPUT = `Invoice INV-2041 has the status "paid".
Amount: $4,280.00`
export default function CodeBlockNotCopyable() {
return <CodeBlock className="max-w-md" code={OUTPUT} copyable={false} />
}what names the content in the name of the copy button, such as "Copy API key".what is "command" for a block with prompt. If not, it is "code".TooltipProvider and the Toaster of the app. See Quick start.CodeBlock also accepts each attribute of the <div> element. CodeBlockPrompt accepts each attribute of the <span> element.
The Copy page gives the keys of labels.
| Prop | Type | Default |
|---|---|---|
code | string | - |
The snippet as plain text, shown verbatim (whitespace and line breaks preserved). It is also what the copy button copies unless | ||
children | ReactNode | - |
Rich content shown instead of | ||
copyValue | string | - |
What the copy button writes to the clipboard. Defaults to | ||
copyable | boolean | - |
Show a copy button. Default | ||
what | string | - |
What is being copied, for the copy button's accessible name and tooltip ("API key" → "Copy API key"). Defaults to "command" when | ||
prompt | string | boolean | false |
Shell prompt shown before every non-empty line of | ||
size | "sm" | "md" | - |
Text size: | ||
wrap | boolean | false |
Wrap long lines (breaking anywhere) instead of scrolling horizontally. Use it in narrow containers where a horizontal scrollbar would hide the end of the line. Default | ||
variant | "block" | "inline" | "terminal" | block |
- | ||
copyPlacement | "side" | "overlay" | overlay |
Where the copy button of a | ||
onCopy | ((value: string) => void) | - |
Called with the copied value each time the user copies it (analytics). | ||
labels | Partial<CopyLabels> | - |
Overrides of the copy button's built-in texts ("Copy <what>", "Copied"), to translate or reword them. See | ||
| Prop | Type | Default |
|---|---|---|
children | ReactNode | $ |
Prompt text, | ||