# Chat panel

> A one-on-one messaging panel — contact header, message bubbles, and a composer input.

A shadcn/ui block from the [@quill](https://www.quilldesignsystem.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/quill/chat).

- Page, with a live preview: https://shadcn.exchange/r/quill/chat
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/quill/chat-light-68ce76c2805044af.png
- Registry item: https://www.quilldesignsystem.com/r/chat.json
- Categories: messaging
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://www.quilldesignsystem.com/r/chat.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `input`, `button`, `https://www.quilldesignsystem.com/r/icon.json`

## Notes from the registry

A one-on-one messaging panel — contact header, message bubbles, and a composer input. Do: Align the current user's messages to one side (right) and the other party's to the other (left) — position is the primary cue for who said what. Don't: Rely on color alone to distinguish sender — pair it with consistent alignment. Use list-detail when you need a list of conversations alongside the open thread, not just the single open thread. Use notifications when the messages are one-way system alerts, not a two-way conversation with someone.

## Files

### `registry/blocks/chat.tsx`

```tsx
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Icon } from '@/components/ui/icon'

const messages = [
  { from: 'them', text: 'Hey! Did the new tokens land?' },
  { from: 'me', text: 'Yep — merged this morning. Dark mode flows automatically now.' },
  { from: 'them', text: 'Amazing. The badges look so much cleaner.' },
  { from: 'me', text: 'Right? Everything binds to the foundation.' },
]

/** A one-on-one messaging panel — contact header, message bubbles, and a composer input. */
export function Chat() {
  return (
    <div className="flex h-[480px] w-[400px] flex-col rounded-xl bg-card text-foreground ring-1 ring-foreground/10">
      <div className="flex items-center gap-3 border-b border-border px-4 py-3">
        <div className="flex size-9 items-center justify-center rounded-full bg-muted text-sm font-medium text-muted-foreground">
          GH
        </div>
        <div className="flex flex-col">
          <span className="text-sm font-medium">Grace Hopper</span>
          <span className="text-xs text-muted-foreground">Online</span>
        </div>
      </div>
      <div className="flex flex-1 flex-col gap-3 overflow-auto p-4">
        {messages.map((m, i) => (
          <div key={i} className={`flex ${m.from === 'me' ? 'justify-end' : 'justify-start'}`}>
            <div
              className={`max-w-[80%] rounded-2xl px-3 py-2 text-sm text-pretty ${
                m.from === 'me' ? 'bg-primary text-primary-foreground' : 'bg-muted text-foreground'
              }`}
            >
              {m.text}
            </div>
          </div>
        ))}
      </div>
      <div className="flex items-center gap-2 border-t border-border p-3">
        <Input placeholder="Message…" className="flex-1" aria-label="Message" />
        <Button size="icon" aria-label="Send">
          <Icon name="arrow_forward" size={18} />
        </Button>
      </div>
    </div>
  )
}
```
