Chat

The Supporter Response building blocks: contact avatars and rows, tags, message bubbles, journey links, timeline events, the reply composer and contact details. Colors come from Colors/chat.

Figma: 10 / Components / Chat
Brandon shared their mission story inYou are not alone
I lost my grandmother to COPD and want to ensure future generations don’t suffer.
Brandon is waiting for a response

Usage

Source: src/components/ui/chat.tsx
import { MessageBubble, ThreadMessage, TimelineEvent } from '@/components/ui/chat'
<ThreadMessage context='Brandon shared their mission story in' journey='You are not alone'>
    <MessageBubble>I lost my grandmother to COPD and want to ensure future generations don’t suffer.</MessageBubble>
</ThreadMessage>
<TimelineEvent kind='waiting'>Brandon is waiting for a response</TimelineEvent>

ContactAvatar

A 40px avatar on Colors/surface/muted with the mission (heart) and high-intent (rocket) indicators above it. Pass src for an approved photo.
BSGLJM

Tags

Default and AI suggested tags, each with an optional remove. Suggested tags keep the dashed Colors/chat/ai/accent border; selecting one adds it.
Host EventMonthly Donor

Message bubbles

One bubble per direction, Roboto 16 / 24 with 16px corners. Incoming has a border; outgoing squares its top left corner.
I lost my grandmother to COPD and want to ensure future generations don’t suffer.
I lost my grandmother to COPD and want to ensure future generations don’t suffer.

Thread details

JourneyLink belongs with message context; ContactGroupHeader groups the contact list by day.
You are not alone
Yesterday5

Contact rows

Two-line rows in default, unread (medium summary and a dot), selected (Colors/chat/row/selected) and done (Colors/surface/subtle). Select a row to try it.

Timeline events

Status lines in the conversation. The AI draft uses the GoodUnited AI sparkle.
Brandon is waiting for a response
GoodUnited AI drafted a response for Brandon
You replied · 12:36 AM, Aug 16, 2026
You copied the response and replied via email
Marked as done

Reply channels

Messenger or email for the reply. Email switches the composer to copy-and-open.

Reply composer

The drafted reply in the composer gradient frame, the writing-style and feedback footer, and the already-sent guard. Send, then Write another.

Reply composer, email

channel email adds the subject and ends with Copy and open email.

Contact details

One line each for the location, the Messenger name and the email in the supporter profile.
Location: Portland, Oregon
Messenger: Brandon Smith
Email: brandon@example.com

When to use

When to reach for it, and when to use something else.

Use it for

Complete: Supporter Response screens, composed into ContactList, ConversationPane and SupporterProfile (Blocks / Supporter Response).
Complete: Incoming bubbles for what supporters shared, outgoing bubbles for replies that went out.
Complete: The suggested tag kind only for tags GoodUnited AI proposed.

Avoid

Not complete: The Colors/chat tokens outside Supporter Response; use the status and surface tokens elsewhere.
Not complete: A second composer on the same conversation; show SentNotice once a reply went out.

ContactRow

PropTypeDefaultDescription
initialsstring–Shown in the ContactAvatar.
summaryReactNode–Name and topic, Roboto / text-sm.
previewReactNode–The latest message, one line, truncated.
timestring–Roboto / text-xs at the right. Leave it out on done rows.
state'default' | 'unread' | 'selected' | 'done''default'Background and text weight.
mission, intentbooleantrueThe avatar indicators.

ChatTag

PropTypeDefaultDescription
labelstring–The tag name.
kind'default' | 'suggested''default'Suggested adds the dashed AI border.
onSelect() => void–Makes the tag a button, used to accept a suggestion.
onRemove() => void–Shows the remove x.

TimelineEvent

PropTypeDefaultDescription
kind'waiting' | 'ai-draft' | 'replied' | 'email-replied' | 'done'–The icon and its color.

ReplyComposer

PropTypeDefaultDescription
channel'messenger' | 'email'–Messenger ends with Send; email adds the subject and Copy and open email.
message, onMessageChangestring, (value: string) => void–The drafted reply. Send is disabled while it is empty.
subject, onSubjectChangestring, (value: string) => void–Email only.
onSend, onCopyEmail() => void–The primary action for each channel.

ComposerFooter

PropTypeDefaultDescription
onWritingStyle() => void–Opens the writing-style settings.
feedback, onFeedback'up' | 'down' | null–Thumbs up and down on the draft; pressing again clears it.

GoodUnited design system. The Figma file is the source of truth for every color, type size and component.