Saltar al contenido principal
NachUI

Response

La respuesta del asistente como una columna de prosa, con un cursor mientras llegan los tokens y un esqueleto antes del primero.

You can keep the composer and the answer in the same column. Three things make it read well:

  • Render markdown outside the component and pass the result as children.
  • Keep code in a block with its own copy button.
  • Show the caret only while tokens are still arriving.
const answer = await model.generate({
  prompt: 'Summarise this thread',
  maxTokens: 200,
});
1'use client';
2
3import { CodeBlock } from '@/components/ui/code-block';
4import { Response } from '@/components/ui/response';
5
6const CODE = `const answer = await model.generate({
7 prompt: 'Summarise this thread',
8 maxTokens: 200,
9});`;
10
11export function Default() {
12 return (
13 <div className="w-full max-w-lg">
14 <Response>
15 <p>
16 You can keep the composer and the answer in the same column. Three things make it read
17 well:
18 </p>
19 <ul>
20 <li>
21 Render markdown outside the component and pass the result as <code>children</code>.
22 </li>
23 <li>Keep code in a block with its own copy button.</li>
24 <li>Show the caret only while tokens are still arriving.</li>
25 </ul>
26 <CodeBlock code={CODE} language="ts">
27 <CodeBlock.CopyButton />
28 <CodeBlock.Content />
29 </CodeBlock>
30 </Response>
31 </div>
32 );
33}

Instalación

pnpm dlx nachui add response

Anatomía

1import { Response } from '@/components/ui/response';
1<Response isStreaming={status === 'streaming'}>
2 <ReactMarkdown>{message.content}</ReactMarkdown>
3</Response>
Response no parsea markdown. Le da estilo a lo que renderices adentro: párrafos, títulos, listas, código inline y citas reciben el espaciado y la tipografía de una respuesta, y un CodeBlock entra tal cual. Renderizá el markdown con react-markdown o con tu propio pipeline y pasá el resultado como children, así el componente sigue sin dependencias y el renderer lo controlás vos.

Composición

Usá la siguiente composición para construir un Response:
Response
├── Response.Content
└── Response.Caret
Response.Skeleton

Streaming

Mientras isStreaming es true, un cursor parpadea después del último nodo y la raíz lleva aria-busy. Antes del primer token no hay nada que mostrar, así que renderizá Response.Skeleton en su lugar: tres líneas con brillo que se leen como una respuesta escribiéndose.

Reading the question and what came before it

Pulling the parts of the answer together

Writing it down

1'use client';
2
3import { useEffect, useState } from 'react';
4import { Response } from '@/components/ui/response';
5
6const TEXT =
7 'The caret sits after the last character and blinks until the stream closes. Before the first token arrives, the skeleton takes its place so the column never sits empty.';
8
9export function Streaming() {
10 const [count, setCount] = useState(0);
11 const [running, setRunning] = useState(true);
12
13 useEffect(() => {
14 if (!running) return;
15 if (count >= TEXT.length) {
16 setRunning(false);
17 return;
18 }
19 const timer = setTimeout(() => setCount((value) => value + 2), 30);
20 return () => clearTimeout(timer);
21 }, [count, running]);
22
23 const restart = () => {
24 setCount(0);
25 setRunning(true);
26 };
27
28 return (
29 <div className="flex w-full max-w-lg flex-col gap-4">
30 <button
31 type="button"
32 onClick={restart}
33 className="border-border hover:bg-muted w-fit rounded-full border px-3 py-1.5 text-xs transition-colors"
34 >
35 Stream again
36 </button>
37 {count === 0 ? (
38 <Response.Skeleton />
39 ) : (
40 <Response isStreaming={running}>
41 <p>{TEXT.slice(0, count)}</p>
42 </Response>
43 )}
44 </div>
45 );
46}

Referencia de API

Response

PropTypeDefaultDescription
isStreamingbooleanfalseMuestra el cursor y setea aria-busy
classNamestring-Clases CSS adicionales

Response.Content

PropTypeDefaultDescription
classNamestring-Clases CSS adicionales

Response.Caret

PropTypeDefaultDescription
classNamestring-Clases CSS adicionales

Response.Skeleton

PropTypeDefaultDescription
linesstring[]tres líneas de rellenoTexto de cada línea con brillo
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