# A stop generation button is available during generation

- **Pattern:** `ab-000142` (`ai-chat-visibility.loading-and-streaming.stop-generation-button`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000142
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000142)

## Why it matters

Without a stop button the user is held hostage by every generation they regret starting: a prompt that is clearly going off the rails, a response already too long, a hallucination cascading into more hallucinations. They cannot terminate the stream, cannot re-prompt, and the product burns their tokens and wall-clock time on output they will immediately delete. This is one of the most-cited usability gaps in AI chat products and directly affects token-spend efficiency for paying users.

## Severity rationale

High because users cannot recover from a bad generation and the product wastes their tokens on discarded output.

## Remediation

In `src/components/chat/ChatInput.tsx`, swap the Send button for a Stop button while `isLoading` is true and wire it to the `stop()` function from `useChat` (or to `controller.abort()` for custom `AbortController`-based fetches). The partial response should remain visible after stopping.

```tsx
{isLoading ? (
  <Button onClick={stop} variant="destructive">Stop</Button>
) : (
  <Button type="submit">Send</Button>
)}
```

## Detection

- **ID:** `stop-generation-button`
- **Severity:** `high`
- **What to look for:** Check whether a stop/cancel button appears while the AI is generating a response. In the Vercel AI SDK, this is the `stop()` function from `useChat`. In custom implementations, look for AbortController usage that allows cancellation. The button should be visible and functional during streaming. Count the cancellation mechanisms present (AbortController, `stop()`, custom abort logic).
- **Pass criteria:** A stop/cancel button is rendered and functional while generation is in progress. Clicking it halts the stream and leaves the partial response visible. The input becomes re-enabled after stopping. At least 1 abort mechanism must be wired to the button.
- **Fail criteria:** No stop button exists, or a stop button exists but is always disabled or hidden. Users must wait for the full response to complete even if it is clearly wrong or too long.
- **Skip (N/A) when:** The AI interface operates in strictly non-streaming mode and responses are short enough that stopping is not meaningful (average response under 2 seconds). Signal: no streaming detected in API calls and responses are short-form.
- **Detail on fail:** `"No stop generation button found; users cannot interrupt long or incorrect responses during generation"`
- **Remediation:** In your input component at `src/components/chat/ChatInput.tsx`, toggle between Send and Stop:

  ```tsx
  {isLoading ? (
    <Button onClick={stop} variant="destructive">Stop</Button>
  ) : (
    <Button type="submit">Send</Button>
  )}
  ```

  For custom fetch implementations, create an AbortController, pass its signal to the fetch call, and invoke `controller.abort()` on the stop button click.
- **Cross-reference:** For button state management and accessible toggle patterns, the Accessibility Fundamentals Audit covers dynamic ARIA state changes.

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-000142
