---
title: Composer
description: The chat composer from the Notra dashboard, a muted tray around the input card.
---

<Component path="composer/examples/composer" />

<RegistryInstall name="composer" />

The frame is a muted tray with the input card inside. The toolbar buttons and the send button are the Notra `Button`, the input is the shadcn `Textarea` with its field chrome removed, because the card is the field. The send tooltip is the Notra `Tooltip`. A disabled send button stays focusable, so the tooltip can still say why it is disabled.

```tsx
<ComposerFrame>
  <ComposerInput aria-label="Message" placeholder="Send a message..." rows={1} />
  <ComposerToolbar>
    <ComposerToolbarButton>
      Auto
    </ComposerToolbarButton>
    <div className="ml-auto flex items-center gap-1">
      <ComposerToolbarButton aria-label="Attach files" size="icon-sm">
        <PlusIcon />
      </ComposerToolbarButton>
      <ComposerSend disabled={!value} label="Send message" tooltip="Send">
        <ArrowUpIcon className="size-4" />
      </ComposerSend>
    </div>
  </ComposerToolbar>
</ComposerFrame>
```

## Queue and attachments

Pass a `ComposerNudge` to `nudge` and it slides in on the tray above the card. Queued messages and files are `ComposerChip`s. Each chip shows the actions you give it: send now, edit and remove.

<Component path="composer/examples/composer-queue" />

## States

Every state the dashboard composer goes through. The send button carries most of them: send, stop, a spinner while stopping or while a queued message waits, and muted while there is nothing to send.

### Empty

Nothing to send yet, so the send button is muted.

<Component path="composer/examples/composer-state-empty" />

### Ready

Text in the input turns send on.

<Component path="composer/examples/composer-state-ready" />

### Streaming

While a reply streams, an empty composer turns send into stop.

<Component path="composer/examples/composer-state-streaming" />

### Stopping

Stop was pressed and the reply is winding down. `busy` swaps the icon for a spinner.

<Component path="composer/examples/composer-state-stopping" />

### Queued

Typing while a reply streams queues the message as a chip on the tray. It can be sent right away, edited or removed.

<Component path="composer/examples/composer-state-queued" />

### Waiting to send

The message waits for the reply to finish. The input is locked and send cancels the queued message.

<Component path="composer/examples/composer-state-waiting" />

### Uploading

Files upload as chips on the tray. A `pending` chip hides its actions, and send waits until every upload is done.

<Component path="composer/examples/composer-state-uploading" />

### Notice

A `title` and an `action` on the nudge show a notice above the card.

<Component path="composer/examples/composer-state-notice" />

### Limit reached

Sending is blocked until the limit resets or the plan changes. The nudge can hold any content, like this warning.

<Component path="composer/examples/composer-state-limit" />

### Flat reply

Flat composers, like comments, only show the tray while there is a nudge.

<Component path="composer/examples/composer-state-flat" />

Rich editors with inline mentions can skip `ComposerInput` and put their own `contentEditable` host in the frame.

| Component | Prop | Default | Description |
| --- | --- | --- | --- |
| `ComposerFrame` | `nudge` | | Shown on the tray above the card, animated in and out. |
| `ComposerFrame` | `flat` | `false` | Tighter radius, no shadow, and no tray until there is a nudge. For inline composers like comments. |
| `ComposerFrame` | `connectedTop` | `false` | Drops the top radius so the frame sits flush under another surface. |
| `ComposerChip` | `onSteer`, `onEdit`, `onRemove` | | Each one adds its action button. Steer and edit hide while `pending`. |
| `ComposerChip` | `onClick` | | Makes the label a button, e.g. to preview a file. |
| `ComposerToolbarButton` | `size` | `"sm"` | Any `Button` size. Use `"icon-sm"` for icon-only actions. |
| `ComposerSend` | `busy` | `false` | Swaps the icon for a spinner. |
| `ComposerSend` | `disabled` | `false` | Mutes the button. It stays focusable for the tooltip. |

The chip action labels default to English, like `Remove ${label}`. Pass `removeLabel`, `editLabel`, `steerLabel` and `previewLabel` to translate them.
