# Response

Response [#response]

The **Response** primitive renders streamed assistant text as markdown and shows a blinking cursor while content is still arriving. It tolerates partial/incomplete markdown — an unterminated code fence mid-stream renders without breaking layout. An optional client-side typewriter reveal animates already-resolved text, and `renderMath` / `renderMermaid` props route `$$…$$` and \`\`\`mermaid blocks to swappable renderers (declare `katex` / `mermaid` in your project if you supply them).

Preview [#preview]

```tsx
'use client';

/**
 * @file response-demo.tsx
 * @description Docs preview for `Response`. Simulates a local token stream by
 * revealing markdown incrementally, showing the streaming cursor and partial
 * (unterminated) code-fence handling, then settling to final markdown.
 */
import * as React from 'react';
import { Response } from '@/components/response';

const FULL = `Here's a quick plan:

1. Load a model **locally** (no server).
2. Stream tokens to the UI.
3. Render \`markdown\` safely, even mid-fence:

\`\`\`ts
const reply = await generateText({ model, prompt });
\`\`\`

All on-device.`;

export default function ResponseDemo() {
  const [text, setText] = React.useState('');
  const [streaming, setStreaming] = React.useState(true);

  React.useEffect(() => {
    let i = 0;
    const id = window.setInterval(() => {
      i += 3;
      setText(FULL.slice(0, i));
      if (i >= FULL.length) {
        window.clearInterval(id);
        setStreaming(false);
      }
    }, 40);
    return () => window.clearInterval(id);
  }, []);

  return (
    <div className="w-full max-w-2xl rounded-lg border border-border bg-card p-4 text-card-foreground">
      <Response streaming={streaming}>{text}</Response>
    </div>
  );
}
```

Installation [#installation]

```bash
npx shadcn@latest add @localmode/ui/conversation/response
```

Data source & dependencies [#data-source--dependencies]

**Data source:** renders the markdown `string` you stream in — works with any backend. Recommended producer: the token stream from `useChat` / `useGenerateText` in `@localmode/react` (on-device, optional).

* `clsx` + `tailwind-merge` — via the shared `cn()` util (installed automatically as a registry dependency)

Files installed [#files-installed]

* `response.tsx` — the streaming renderer
* `lib/markdown.tsx` — the streaming-safe markdown renderer
* `lib/utils.ts` — the `cn()` helper (if not already present)

Props [#props]

**Response**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` | `string` | — | **Required.** The (possibly partial) markdown content to render. |
| `streaming` | `boolean` | `false` | Whether content is still arriving. When true a blinking cursor is shown after the text and removed on completion. |
| `typewriter` | `boolean` | `false` | Reveal already-resolved text one character at a time. Ignored while `streaming` (live token streams reveal naturally). |
| `typewriterSpeed` | `number` | `2` | Characters revealed per tick when `typewriter` is enabled. |
| `renderMath` | `BlockRenderer` | — | Optional LaTeX/math block renderer (e.g. a KaTeX-backed function). When provided, `$$…$$` blocks are routed to it. Declare `katex` in your project if you supply one. |
| `renderMermaid` | `BlockRenderer` | — | Optional Mermaid diagram renderer. When provided, ```mermaid fences are routed to it. Declare `mermaid` in your project if you supply one. |

Examples [#examples]

Stream tokens [#stream-tokens]

```tsx
import { Response } from '@/components/response';

<Response streaming={isStreaming}>{assistantText}</Response>
```

With KaTeX math [#with-katex-math]

```tsx
// npm i katex
import katex from 'katex';
import 'katex/dist/katex.min.css';

const renderMath = (src: string) => (
  <span dangerouslySetInnerHTML={{ __html: katex.renderToString(src) }} />
);

<Response renderMath={renderMath}>{text}</Response>
```

Customization [#customization]

The cursor is a themed `<span>` — restyle or replace it. The math/diagram renderers are intentionally not bundled; pass your own to keep the installed footprint minimal. The markdown subset lives in `lib/markdown.tsx`.

These primitives are presentational and hook-driven: they render props and emit callbacks, holding only local view state. The orchestration state (e.g. `useChat`) lives in your app. Every surface uses shadcn/ui CSS-variable utilities, so it inherits your theme — restyle the copied file freely.