← All proposals

Chat Message

ChatMessage, with sender: user or agent.

Net-new componentOpen in Storybook

proposals/ChatMessage/decisions.md18 lines · View on GitHub

Decisions

  • One component, two variants. User and agent messages are the same kind of thing (a turn in a conversation) with the same slots and the same screen-reader need; a chat screen maps over messages with one sender field. They differ in styling and alignment only.
  • sender: agent | user (default agent), not role (collides with the HTML attribute) and not variant (it is set per message by who sent it, not a look picked once per screen).
  • The component owns only the frame: alignment, width, the user bubble, and a hidden sender label. Content is children, because agent messages hold arbitrary content (text, lists, Thinking State, Chain of Thought).
  • label is required and visually hidden (visually-hidden), read before the message. The consumer supplies it ("You", "Zappy"); no text is hardcoded.
  • User bubble: --pds-color-surface-default-secondary fill, --pds-border-radius-card, padding 2xs block and s inline, hugs its content to a max of 80% of the width (--chat-message-max-width, a component variable without the --pds- prefix). white-space: pre-wrap keeps line breaks the user typed.
  • Agent message: no container, full width, same text styles (size s, default foreground).
  • ChatMessageList owns the gap between turns: a thin flex column with --chat-message-list-gap (--pds-spacing-l, 20px, a first pick to check against the design). It exists so the spacing is a real, annotated part of the proposal (Annotate only shows gaps on net-new parts) and a place for the list behavior later. The consumer adds role / aria-label (for example role='log' for a streaming conversation) until that is designed. Same folder and Storybook entry as ChatMessage.
  • Agent lists: ul / ol inside an agent message get --pds-spacing-l start padding, because the PDS reset removes list padding and the markers were clipped.
  • Not the message's job: scroll and live region, an avatar, agent actions (copy, regenerate, feedback), user extras (attachments, edit, timestamps). Open: which of these next, starting with the list.
  • Element: a div, so the list can wrap each in an li or whatever its semantics need.
  • Storybook: Proposals/Chat Message. Marked new-pattern.
  • Open: confirm the bubble radius and the 80% width against the design, and check the fill in dark mode.
  • Rich agent content is the engineers' to render, not ChatMessage's. ChatMessage does not style the HTML a markdown renderer emits (paragraphs, headings, strong, links, inline code). The engineer maps those in the renderer. Fenced code blocks map to the PDS CodeBlock (copy button included). PDS has no inline code style, so the reference is Erika's screenshot (~/Desktop/Screenshot 2026-10-13 at 11.36.38 AM.png): a small chip in the code font (--pds-typography-ff-code) with a light surface fill, a thin border, a small radius and a little inline padding. Exact tokens are for the engineer to pick against the design. Open: should this become a PDS InlineCode later?
  • One exception: ul / ol inside an agent message keep --pds-spacing-l start padding, a one-line rule, because the PDS reset removes list padding and the markers were clipped. Say if you'd rather the renderer own that too.
  • Spacing between blocks inside an agent message (text, then a Suggestion Card) is the renderer's, not ChatMessage's. The reference value is the same as between turns (--pds-spacing-l, 20px); the Suggestion Card InChat story shows it. Open: should ChatMessage own it for its children instead?