# Prompt Suggestions

> Starter prompts for empty chat states — chips, cards or a list that rise in with a short stagger and fill the composer when clicked.

- **Slug:** `prompt-suggestions` · **Category:** input · **Status:** beta
- **Import:** `import { PromptSuggestion, PromptSuggestions } from "@kura-ui/react/prompt-suggestions";`
- **Docs:** https://kuro.abstergo.fyi/components/prompt-suggestions
- **Registry item:** https://kuro.abstergo.fyi/r/prompt-suggestions.json
- **Tags:** suggestions, starters, empty-state, prompts, chips, onboarding, stagger

## Install

```bash
# shadcn registry (copies source into your project)
npx shadcn@latest add https://kuro.abstergo.fyi/r/prompt-suggestions.json
# Kura CLI (same, plus dependency resolution and --json output)
npx @kura-ui/cli add prompt-suggestions
# npm package
npm install @kura-ui/react
```

## When to use

- The empty state of a chat or agent: show 3–6 example prompts the user can start from.
- Follow-up suggestions under an answer (“Make it shorter”, “Add sources”) using the chips variant.
- Onboarding that teaches what the assistant can do, with icons and one-line descriptions.

## When not to use

- Commands typed inline in the prompt — use slash-command-menu.
- Global actions and navigation — use command-palette.
- More than ~8 items or anything that needs search — use command-palette or a list.

## Props

| Prop | Type | Default | Required | Description |
| --- | --- | --- | --- | --- |
| `suggestions` | `readonly PromptSuggestion[]` | — | yes | Items: { id?, title, description?, icon?, prompt? }. `prompt` defaults to title + description. |
| `onSelect` | `(prompt: string, suggestion: PromptSuggestion) => void` | — | no | Called with the prompt text on click — typically sets the composer value. |
| `variant` | `"chips" \| "cards" \| "list"` | `"cards"` | no | chips = wrapping pills (titles only), cards = two-column tiles with icon and description, list = hairline-separated rows. |
| `stagger` | `number` | `0.04` | no | Seconds between items entering (30–50ms reads best). Capped after 8 items. |
| `label` | `string` | `"Suggestions"` | no | Accessible name of the list. |
| `disabled` | `boolean` | `false` | no | Disable every suggestion. |

Native attributes of the root element, `className` and `ref` are passed through.

## Anatomy

- **PromptSuggestions** (`data-slot="prompt-suggestions"`) — <ul> root; data-variant = chips | cards | list.
- **PromptSuggestionsItem** (`data-slot="prompt-suggestions-item"`) — Each suggestion is a native <button>; an arrow fades in on hover/focus (cards, list).
- **PromptSuggestionsIcon** (`data-slot="prompt-suggestions-icon"`) — Optional icon; a 28px tile in cards.

## Accessibility

- A labelled <ul> of native buttons; each button's name is its title (plus description).
- Icons and the hover arrow are aria-hidden.
- After filling a composer, move focus to its textarea so the user can edit and send (see the composition example).
- Reduced motion: Items fade in together-ish without rising or blurring; hover arrows and press scales do not move.

| Keys | Action |
| --- | --- |
| Tab / Shift+Tab | Move between suggestions |
| Enter / Space | Select a suggestion |

## Notes for agents

- Give items stable `id`s; changing the array with new ids animates the swap (old items fade out, new ones stagger in).
- Keep titles under ~6 words; put detail in `description` (cards/list only — chips show the title).
- To fill a Composer: control its `value`, call setValue(prompt) in onSelect, then focus the ComposerInput ref.
- Hide the suggestions once the conversation has messages; they are an empty-state affordance.

## Examples

### Chips (minimal)

```tsx
"use client";

import { PromptSuggestions } from "@kura-ui/react/prompt-suggestions";

export function PromptSuggestionsMinimal() {
  return (
    <PromptSuggestions
      variant="chips"
      suggestions={[
        { title: "Summarize a PDF" },
        { title: "Write a SQL query" },
        { title: "Plan a sprint" },
        { title: "Explain a regex" },
      ]}
      onSelect={(prompt) => console.log(prompt)}
    />
  );
}
```

### Cards with icons and refresh (full)

Swap the set to see items leave and stagger back in.

```tsx
"use client";

import { BookOpen, Bug, Calendar, ChartLine, Mail, Plane, RefreshCw, Scale, Telescope } from "lucide-react";
import * as React from "react";
import { Button } from "@kura-ui/react/button";
import { type PromptSuggestion, PromptSuggestions } from "@kura-ui/react/prompt-suggestions";

const sets: PromptSuggestion[][] = [
  [
    {
      id: "trip",
      title: "Plan a trip",
      description: "Four slow days in Kyoto in early April",
      icon: <Plane />,
    },
    {
      id: "metrics",
      title: "Analyze metrics",
      description: "Why did weekly actives dip after the release?",
      icon: <ChartLine />,
    },
    {
      id: "email",
      title: "Draft an email",
      description: "Decline a meeting without closing the door",
      icon: <Mail />,
    },
    {
      id: "bug",
      title: "Debug a crash",
      description: "TypeError: cannot read properties of undefined",
      icon: <Bug />,
    },
  ],
  [
    {
      id: "learn",
      title: "Teach me",
      description: "How transformers attend, with a tiny example",
      icon: <BookOpen />,
    },
    {
      id: "compare",
      title: "Compare options",
      description: "Postgres vs. SQLite for a local-first app",
      icon: <Scale />,
    },
    {
      id: "research",
      title: "Research",
      description: "What changed in the EU AI Act this year",
      icon: <Telescope />,
    },
    {
      id: "week",
      title: "Plan my week",
      description: "Fit deep work around six meetings",
      icon: <Calendar />,
    },
  ],
];

export function PromptSuggestionsFull() {
  const [set, setSet] = React.useState(0);
  const [picked, setPicked] = React.useState<string | null>(null);
  return (
    <div className="flex w-full max-w-xl flex-col gap-3">
      <PromptSuggestions
        variant="cards"
        label="Try one of these"
        stagger={0.05}
        suggestions={sets[set] ?? []}
        onSelect={(prompt) => setPicked(prompt)}
      />
      <div className="flex items-center justify-between gap-3 px-1">
        <p className="min-w-0 truncate text-kura-fg-subtle text-xs" aria-live="polite">
          {picked ? `Prompt: ${picked}` : "Pick a card"}
        </p>
        <Button variant="ghost" size="xs" onClick={() => setSet((s) => (s + 1) % sets.length)}>
          <RefreshCw />
          More ideas
        </Button>
      </div>
    </div>
  );
}
```

### Empty chat filling a composer (composition)

Selecting a row fills the composer and focuses it for editing.

```tsx
"use client";

import { ChartLine, FlaskConical, Mail } from "lucide-react";
import * as React from "react";
import {
  Composer,
  ComposerActions,
  ComposerAttachButton,
  ComposerInput,
  ComposerSubmit,
  ComposerToolbar,
  ComposerTools,
} from "@kura-ui/react/composer";
import { type PromptSuggestion, PromptSuggestions } from "@kura-ui/react/prompt-suggestions";

const starters: PromptSuggestion[] = [
  { title: "Summarize this week's customer feedback", icon: <ChartLine /> },
  { title: "Write tests for the billing service", icon: <FlaskConical /> },
  { title: "Draft a launch announcement", icon: <Mail /> },
];

export function PromptSuggestionsEmptyChat() {
  const [value, setValue] = React.useState("");
  const input = React.useRef<HTMLTextAreaElement>(null);
  return (
    <div className="flex w-full max-w-xl flex-col gap-5">
      <p className="text-balance text-center font-medium text-2xl text-kura-fg tracking-tight">
        What should we work on?
      </p>
      <Composer value={value} onValueChange={setValue} onSubmit={() => {}}>
        <ComposerInput ref={input} placeholder="Ask anything…" />
        <ComposerToolbar>
          <ComposerTools>
            <ComposerAttachButton />
          </ComposerTools>
          <ComposerActions>
            <ComposerSubmit />
          </ComposerActions>
        </ComposerToolbar>
      </Composer>
      <PromptSuggestions
        variant="list"
        suggestions={starters}
        onSelect={(prompt) => {
          setValue(prompt);
          input.current?.focus();
        }}
      />
    </div>
  );
}
```

## Dependencies

- npm: `lucide-react`, `motion`
- Kura registry items: `kura-theme`, `kura-motion`, `use-reduced-motion`, `utils`
- Related: `composer`, `slash-command-menu`, `command-palette`
