# Composer

> A message to people, written and sent in place, with who it reaches above it and Undo for 8 seconds after Send.

- Name: `composer`
- Status: beta
- Categories: ai, forms
- File: the install writes `composer.tsx` to your `ui` alias, `@/components/ui` by default.
- Other registry items: `@arbokui/motion`, `@arbokui/audience`, `@arbokui/button`, `@arbokui/icon`, `@arbokui/kbd`, `@arbokui/menu`, `@arbokui/peek-card`, `@arbokui/textarea`, `@arbokui/tool-button`, `@arbokui/tooltip`. The install adds them.
- Gallery: https://arbokui.com/components/composer
- Registry item: https://arbokui.com/r/composer.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the component:

   ```bash
   npx shadcn@latest add @arbokui/composer
   ```

## Use it for

- Writing to a team, a group, or one person, under their thread.
- Pass everyone in to, as for Audience. Juniors go by juniorMessages.
- Show the message in its thread from onSend. Take it out in onUndo. Deliver it in onCommit, when the 8 seconds end.
- Pass later with times to offer Send later, like Mon 08:00.

## Avoid it for

- An announcement in a sheet. Put Audience above a Textarea there, and make Send the sheet's main action.
- A one-line reply to a comment. Use Inline Reply.
- Long, formatted writing. Use Editor.

## Props

- `to`: `Recipient[]`. Required. Who the message is for. See Audience.
- `toLabel`: `string`. What the group is called, like Art class. It titles the count's peek and fills the placeholder.
- `juniorMessages`: `"guardians" | "copy"`. Default `"guardians"`. Where messages to juniors go: to their parents instead, or to the junior with their parents copied.
- `placeholder`: `string`. Default `"Write to {toLabel}"`. The field's placeholder.
- `defaultValue`: `string`. Words to start with, like a draft.
- `later`: `{ id: string; label: string; at: string | Date }[]`. Times to offer under Send later. Without it, there is only Send.
- `sendLabel`: `string`. Default `"Send"`. Send's words.
- `onSend`: `(message: { text: string; at: string | Date | null; reach: AudienceReach }) => void`. Pressed: show the message where it lands. at is null for now, or the chosen later time.
- `onUndo`: `(message) => void`. Taken back: take it out of the thread. The words are back in the field. The same object onSend got.
- `onCommit`: `(message) => void | Promise<unknown>`. Final: deliver it now. Return a promise, and a failure turns the button into Retry.
- `onAddGuardian`: `(junior: { person: string; photo?: string }) => void`. The fix for a junior with no parent on file. See Audience.
- `size`: `"sm" | "md" | "lg"`. Default `"md"`. Text, field, and button size.
- `disabled`: `boolean`. Default `false`. Turns the field and the buttons off.
- `className`: `string`. Extra classes on the root. Later classes win.

## Accessibility

- The field is named Message to {toLabel}, and Audience's line describes it, so people hear who it goes to.
- ⌘Enter or Ctrl+Enter sends from the field. Send's tooltip teaches it, and Send has aria-keyshortcuts.
- Send says what happened in its name: Sent to 3, then Sent to 3. Press to undo. The page's live region says it once.
- Undo arms a moment after a key press, or when the pointer leaves after a click, so a double press never undoes.
- In the empty field, ⌘Z takes back the message that just went and puts the words back. Anywhere else, ⌘Z does what the page's ⌘Z does.
- Send later is a menu button. Once a time is chosen, it says when, and a press on it undoes.

## Examples

### To a group, with Send later

```tsx
<Composer
  to={group}
  toLabel="Art class"
  later={[{ id: "mon", label: "Mon 08:00", at: "2026-10-26T08:00" }]}
  onSend={(message) => setThread((all) => [...all, message])}
  onUndo={(message) => setThread((all) => all.filter((m) => m !== message))}
  onCommit={(message) => deliver(message)}
/>
```

### To one person

```tsx
<Composer to={[{ person: "Josh Tait" }]} size="sm" />
```
