Chat

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

Figma: 10 / Components / Chat
BSBrandon 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, ShareIndicators, ThreadMessage, TimelineEvent } from '@/components/ui/chat'
<ThreadMessage name='Brandon' initials='BS' src={brandon.photo} context='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' name='Brandon' trailing={<ShareIndicators />}>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

ContactPhoto

The supporter as a small print at the top of the supporter profile: 96px wide in a 4:5 frame, tilted 2° to the left, with a 4px raised frame and shadow-photo, so the person comes first. Without a photo the initials show.
BSJM

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.
Complete: ContactPhoto once per screen, for the person the conversation is with; ContactAvatar everywhere else.

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.
Not complete: Straightening, enlarging or recoloring ContactPhoto, or using it in lists and rows.

ContactPhoto

PropTypeDefaultDescription
initialsstring–Shown when there is no photo, or until it loads.
srcstring–A photo the supporter shared. Cropped to 4:5.
altstring''Leave empty when the name sits beside the photo.

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.
onToggleDone() => void–Adds a 36px square button at the right on hover or keyboard focus: ChatDoneIcon marks the conversation as done, ChatOpenIcon as undone. It sits beside the row button, never inside it.
donebooleanfalseWhich of the two the button offers.

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 in its 24px circle, sitting on the thread line.
namestring–Shown first in Colors/text/primary.
trailingReactNode–After the text, for example ShareIndicators.

ThreadMessage

PropTypeDefaultDescription
name, contextstring, ReactNode–The sender in Colors/text/primary, then what they shared in Colors/text/secondary.
initials, srcstring–The 24px avatar that starts the thread line. Without initials, a person icon in a circle.
journeystring–The JourneyLink pill.

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.