Saltar al contenido principal
NachUI

Code Block

Un bloque de código con botón de copiar, números de línea opcionales y un pliegue para snippets largos. Sin highlighter atado.

import { CodeBlock } from '@/components/ui/code-block';

export function Snippet() {
  return (
    <CodeBlock code={source} language="tsx">
      <CodeBlock.CopyButton />
      <CodeBlock.Content />
    </CodeBlock>
  );
}
1'use client';
2
3import { CodeBlock } from '@/components/ui/code-block';
4
5const CODE = `import { CodeBlock } from '@/components/ui/code-block';
6
7export function Snippet() {
8 return (
9 <CodeBlock code={source} language="tsx">
10 <CodeBlock.CopyButton />
11 <CodeBlock.Content />
12 </CodeBlock>
13 );
14}`;
15
16export function Default() {
17 return (
18 <div className="w-full max-w-lg">
19 <CodeBlock code={CODE} language="tsx" showLineNumbers>
20 <CodeBlock.CopyButton />
21 <CodeBlock.Content />
22 </CodeBlock>
23 </div>
24 );
25}

Instalación

pnpm dlx nachui add code-block

Anatomía

1import { CodeBlock } from '@/components/ui/code-block';
1<CodeBlock code={source} language="tsx" showLineNumbers>
2 <CodeBlock.CopyButton />
3 <CodeBlock.Content />
4</CodeBlock>
El código entra como string en la raíz y todas las partes lo leen de ahí. No hay encabezado: el botón de copiar flota arriba a la derecha y aparece al pasar el mouse, así que el bloque es solo el código.

Composición

Usá la siguiente composición para construir un CodeBlock:
CodeBlock
├── CodeBlock.CopyButton
├── CodeBlock.Content
└── CodeBlock.Expand

Plegar código largo

Con collapsible el contenido se corta en maxLines. CodeBlock.Expand renderiza el botón, y solo cuando hay algo que mostrar.
export const steps = [
  { id: 1, label: 'Step 1', done: true },
  { id: 2, label: 'Step 2', done: true },
  { id: 3, label: 'Step 3', done: true },
  { id: 4, label: 'Step 4', done: true },
  { id: 5, label: 'Step 5', done: true },
  { id: 6, label: 'Step 6', done: true },
  { id: 7, label: 'Step 7', done: true },
1'use client';
2
3import { CodeBlock } from '@/components/ui/code-block';
4
5const CODE = Array.from({ length: 24 }, (_, index) =>
6 index === 0
7 ? 'export const steps = ['
8 : index === 23
9 ? '];'
10 : ` { id: ${index}, label: 'Step ${index}', done: ${index < 12} },`,
11).join('\n');
12
13export function Collapsible() {
14 return (
15 <div className="w-full max-w-lg">
16 <CodeBlock code={CODE} language="ts" collapsible maxLines={8}>
17 <CodeBlock.CopyButton />
18 <CodeBlock.Content />
19 <CodeBlock.Expand />
20 </CodeBlock>
21 </div>
22 );
23}

Resaltado de sintaxis

No trae ninguno, a propósito: un highlighter es la única dependencia que duplicaría el tamaño de este archivo. Pasá renderLine y devolvé lo que te dé tu highlighter por cada línea, tokens de Shiki incluidos.
1<CodeBlock code={source} renderLine={(line, index) => highlight(line, index)}>
2 <CodeBlock.Content />
3</CodeBlock>

Referencia de API

CodeBlock

PropTypeDefaultDescription
codestring-El código a mostrar y copiar
languagestring-Va en data-language y como language-* en el code
showLineNumbersbooleanfalseAgrega un margen con números de línea
collapsiblebooleanfalseCorta el contenido en maxLines hasta expandir
maxLinesnumber20Líneas visibles mientras está plegado
renderLine(line: string, index: number) => ReactNode-Renderiza cada línea, para enchufar un highlighter
classNamestring-Clases CSS adicionales

CodeBlock.CopyButton

PropTypeDefaultDescription
copyLabelstring'Copy code'Nombre accesible en reposo
copiedLabelstring'Copied'Nombre accesible durante 1,5 s después de copiar
onCopied(code: string) => void-Se llama después de escribir al portapapeles
classNamestring-Clases CSS adicionales

CodeBlock.Content

PropTypeDefaultDescription
classNamestring-Clases CSS adicionales

CodeBlock.Expand

PropTypeDefaultDescription
expandLabel(hidden: number) => stringShow {n} more linesEtiqueta mientras está plegado
collapseLabelstring'Show less'Etiqueta mientras está expandido
classNamestring-Clases CSS adicionales
¿Encontraste algo que mejorar?

¿Notaste un error, tipografía o detalle faltante en esta página? Ayúdanos a mejorar la documentación abriendo un issue en GitHub.

Crear un Issue