# Composer (goodtabs UI)

A message field that grows as you type, with a character count and a send button.

## Install

```bash
npx shadcn@latest add https://ui.goodtabs.co/r/composer.json
```

Or, with the @goodtabs namespace configured in components.json: `npx shadcn@latest add @goodtabs/composer`

## Usage

```tsx
import { Composer } from "@/components/ui/composer"

<Composer placeholder="Reply" maxLength={500} onSubmit={(text) => send(text)} />
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| value | `string` |  | Controlled text. Leave out for an uncontrolled composer. |
| defaultValue | `string` | `""` | Starting text for the uncontrolled form. |
| onValueChange | `(value: string) => void` |  | Fires with the new text on every change and with an empty string after a send. |
| onSubmit | `(text: string) => void` |  | Called with the trimmed text when send is clicked or Cmd or Ctrl plus Enter is pressed. |
| maxLength | `number` |  | Hard limit on characters, shown next to the count. |
| placeholder | `string` | `"Write a message"` | Placeholder for the empty field. |
| sendLabel | `string` | `"Send"` | Label of the send button. |
| leading | `ReactNode` |  | Slot at the left of the bottom bar, for an attach button or a hint. |
| maxRows | `number` | `8` | Rows the field grows to before it scrolls. |
| disabled | `boolean` | `false` | Disables the field and the send button. |

## When to use

- Chat, comment and reply fields at the bottom of a thread
- Short posts and updates with a character limit
- Anywhere a textarea needs a send action and a keyboard shortcut built in

## When not to use

- Long form writing: use the auto textarea or an editor
- Forms with several fields and one submit button
- Fields that submit on plain Enter, such as a command line

## Notes for agents

- Client component that takes functions: a demo or page passing onSubmit or onValueChange must be a client component too
- After a send it clears the field and calls onValueChange with an empty string, so controlled parents clear without extra code
- The leading slot is plain children: pass a ghost icon-sm Button for attach, and a Kbd hint if you want one. kbd is listed as a dependency for that demo
- aria-label names the field and defaults to Message; className goes on the surface, so set widths there

Docs: https://ui.goodtabs.co/components/composer