# Dialogue box

Dialogue box is a neobrutalist React component from Cruise UI. A game-style speech box for tours and tips: portrait, name tab, typewriter text, Next / Skip and a step count.

Install (with the @cruiseui registry in components.json, see Installation):

```bash
npx shadcn@latest add @cruiseui/dialogue-box
```

Import: `import { CruiseDialogueBox } from "@/components/cruise/dialogue-box";`

## When to use

Onboarding tours, tips from a character, story moments in games.

## When not to

Important instructions people need to find again (put them on the page).

## Example (React)

```tsx
"use client";

import { useState } from "react";
import { CruiseAvatar } from "@/components/cruise/avatar";
import { CruiseButton } from "@/components/cruise/button";
import { CruiseDialogueBox } from "@/components/cruise/dialogue-box";

const steps = [
  { text: "Welcome to Cruise UI! I'll show you around in three quick steps." },
  { text: "Pick a city theme in the Studio, then tweak the colours, borders and corners." },
  { text: "Copy the prompt into your AI, or install the components into your React app." },
];

export default function DialogueBoxExample() {
  const [key, setKey] = useState(0);
  const [done, setDone] = useState(false);
  if (done) {
    return (
      <CruiseButton variant="secondary" onClick={() => (setDone(false), setKey((k) => k + 1))}>
        Show the tour again
      </CruiseButton>
    );
  }
  return (
    <CruiseDialogueBox
      key={key}
      speaker="Ada"
      portrait={<CruiseAvatar name="Ada Okafor" size="lg" />}
      steps={steps}
      onSkip={() => setDone(true)}
      onFinish={() => setDone(true)}
    />
  );
}
```

## HTML

Needs theme.css (https://cruiseui.dev/theme.css).

```html
<section class="dialogue" aria-label="Ada says">
  <span class="dialogue-name">Ada</span>
  <div class="dialogue-main">
    <p class="dialogue-text"><span class="visually-hidden" aria-live="polite">Pick a city theme in the Studio, then tweak the colours.</span><span aria-hidden="true">Pick a city theme in the Studio, then tweak the colours.</span></p>
    <div class="dialogue-foot">
      <span class="dialogue-step"><span class="visually-hidden">Step </span>2 / 3</span>
      <div class="dialogue-buttons">
        <button type="button" class="brutal btn btn-secondary">Skip</button>
        <button type="button" class="brutal btn on-primary">Next</button>
      </div>
    </div>
  </div>
</section>
```

## Props: CruiseDialogueBox

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `steps` | `CruiseDialogueStep[]` | — | — |
| `speaker?` | `string` | — | Default speaker for every step. |
| `portrait?` | `ReactNode` | — | Default portrait (an avatar or character), left of the text. |
| `typewriter?` | `boolean` | `true` | Type each line out. |
| `speed?` | `number` | `28` | Milliseconds per character when typing. |
| `position?` | `"inline" \| "fixed"` | `"inline"` | — |
| `onFinish?` | `(() => void)` | — | After the last step's "Done". |
| `onSkip?` | `(() => void)` | — | "Skip" (all steps). Without it, there's no Skip button. |
| `className?` | `string` | — | — |

## Accessibility

- Screen readers get the whole line at once; the typing is visual only.
- Click, Enter or "Show all" reveals the full line; reduced motion shows it straight away.
- Next, Skip and Done are real buttons; the step count reads "Step 2 / 5".
