# Message Row

> A message with quick actions. Pointing at it or moving focus into it springs in Reply, and Edit on your own, with R and E keys. A reply or an edit opens in place.

- Name: `message-row`
- Status: beta
- Categories: ai, display
- File: the install writes `message-row.tsx` to your `ui` alias, `@/components/ui` by default.
- Other registry items: `@arbokui/avatar`, `@arbokui/hover-actions`, `@arbokui/inline-reply`, `@arbokui/motion`, `@arbokui/peek-card`, `@arbokui/peek-person`, `@arbokui/person`, `@arbokui/row-actions`. The install adds them.
- Gallery: https://arbokui.com/components/message-row
- Registry item: https://arbokui.com/r/message-row.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/message-row
   ```

## Use it for

- Messages in a chat, a team feed, or an activity list, stacked in a card like list rows.
- Set own on the viewer's messages, so they get Edit. Pass me, so a new reply shows their name and photo.
- Save what onAction hands you. The reply or edit already shows in place, and new props with it replace the local copy.
- Give peek the author's role, team, and next event, so their name opens a card.

## Avoid it for

- A new message to a group. Use Composer, which says who it reaches.
- Rows that are not messages, like orders or files. Use a list row.
- Extra actions without a one-key shortcut. Each row's keys are how the keyboard reaches them fast.

## Props

- `author`: `{ person: string; photo?: string } | string`. Required. Who posted it. Initials show until the photo loads.
- `time`: `string`. Required. When, like "18:02".
- `text`: `string`. Required. The message. Line breaks show.
- `own`: `boolean`. Default `false`. The viewer's own message: adds Edit, with E.
- `me`: `{ person: string; photo?: string } | string`. Default `"You"`. Who is replying, so a new reply shows their name and photo.
- `context`: `string`. Where it was posted, like "in Design". It follows the time.
- `replies`: `MessageReply[]`. Replies already there, each { author, text }.
- `onAction`: `(action: "reply" | "edit", text: string) => void`. A reply was sent or the message was edited, and it shows in place. Save it here.
- `peek`: `Omit<PeekCardProps, "person" | "photo">`. The author's peek, like role, team, and next event. Without it, the name is plain.
- `extraActions`: `HoverAction[]`. More quick actions after Reply and Edit, like Pin. Give each a one-key shortcut.
- `divider`: `boolean`. Default `true`. A 1px hairline under it, inset to its padding. The last row has none.
- `className`: `string`. Extra classes on the row. Later classes win.

## Accessibility

- Each message is an article, named by its author and time, and a Tab stop of its own.
- Focus on the message, or anywhere in it, shows its actions, the same as pointing at it. R replies and E edits while they show.
- The keys stay quiet while you type in a field.
- Reply puts the cursor in a field named Reply to {first name}. Enter sends, and Esc cancels without closing anything around it.
- When the reply or edit closes by Enter or Esc, focus comes back to the message, so the keyboard keeps its place. An empty reply, or an edit left as it was, closes when focus leaves it for somewhere else, and focus stays there.
- While a field is open, a press on the message's words or space keeps the cursor in the field, so a double click on Reply still types into it.
- Replies are a list named Replies to {author}. The hairline is a border, so it stays in forced colors.

## Examples

### A plain message, with its time

```tsx
<MessageRow author={{ person: "Anna Price" }} time="18:02" text="Team sync moves to Room 3 on Wednesday." />
```

### Your own, with replies saved

```tsx
<MessageRow
  author={me}
  me={me}
  own
  time="18:10"
  context="in Design"
  text={message.text}
  replies={message.replies}
  onAction={(action, text) => (action === "edit" ? saveEdit(message.id, text) : saveReply(message.id, text))}
/>
```

### With a peek on the name

```tsx
<MessageRow
  author={{ person: "Sam Carter" }}
  time="Mon 09:12"
  text="Demo day is Tuesday at 6."
  peek={{ subtitle: "Head of design · Design", facts: [["Next", "Design review, Tue 19:00"]] }}
/>
```
