Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelogApp ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbarAnchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree ViewAccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual ListActivity HeatmapAnimated NumberBadgeBar ListChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveformBlockquoteCode BlockCode GroupGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriterButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerField ListFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree SelectAlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip
ARC UIARC Radiant Components
v4.9DocsComponentsTokensSynthesizer
Getting StartedFrameworksServer RenderingDesign TokensThemingTheme SynthesizerTypographyUtilitiesAll ComponentsAccessibilityBrowser SupportChangelogContributingStatsApp ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbarAnchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree ViewAccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual ListActivity HeatmapAnimated NumberBadgeBar ListChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveformBlockquoteCode BlockCode GroupGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriterButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerField ListFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree SelectAlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip

Conversation

An AI chat transcript: role-attributed messages in a scrollable column that follows new replies without yanking a reader who scrolled up. For AI assistant panels.

ComponentsConversation
feedbackinteractive
<arc-conversation>

Overview

Conversation is the transcript surface for an AI assistant panel. Slot `<arc-message>` children into it and each one takes a voice from its speaker attribute: user messages align to the inline end on a faint accent tint, assistant messages answer from the inline start on a neutral surface, and system messages run centered and muted for notices in the transcript's own voice. Because alignment is built on logical properties, the whole layout mirrors in RTL. The container is the scroll area, and it follows one rule: while the reader is near the bottom, new or growing messages keep the view pinned to the latest; once they scroll up to re-read, the transcript stays put. The `arc-scroll-away` and `arc-scroll-return` events report those transitions with the distance from the bottom, so a consumer can float a "jump to latest" chip and wire it to the `scrollToEnd()` method. Streaming needs no API of its own: a message body is its default slot, so appending text to the slot streams the reply in. With the `markdown` attribute set, the slotted text renders through the markdown renderer and re-parses as it grows, and a `pending` message shows the typing indicator until the first tokens arrive. The transcript server-renders in full, typing dots included.

Guidelines

When to use

  • Use Conversation for a dialogue between the user and a responder, where role attribution and scroll behavior matter
  • Stream a reply by appending to the message's slotted text (for example, updating textContent as tokens arrive); with markdown set it re-renders as it grows
  • Show a pending assistant message the moment a request is sent, then fill its slot when tokens arrive
  • Give messages timestamps as ISO strings and let the relative-time rendering do the rest
  • Listen for arc-scroll-away to float a "jump to latest" chip, and clear it on arc-scroll-return
  • Size the transcript with the --conversation-height custom property, or let it fill a sized parent

When not to use

  • Do not use Conversation for an activity feed or event history. That is Timeline's job, where entries mark moments rather than speakers
  • Do not use it as a general item column. A List handles collections that no one is talking to
  • Do not scroll the reader to the bottom yourself on new messages; the component already follows, and only when the reader wants it to
  • Do not put critical status in a system message alone; it scrolls away with the transcript
  • Do not add avatars by reflex; the avatar slot is there for products that need one

Features

  • Three message voices: user on an accent tint at the inline end, assistant on a neutral surface, system centered and muted
  • Auto-scroll follows new and growing messages, but only while the reader is already near the bottom
  • `arc-scroll-away` / `arc-scroll-return` events with the distance from the bottom, for a "jump to latest" chip
  • `scrollToEnd()` method to jump the transcript to its newest message
  • Streaming-friendly: append text to a message slot and the view keeps up
  • Markdown rendering of message bodies through `arc-markdown`, re-parsed as streamed text grows
  • Typing indicator on `pending` messages, replaced by a static ellipsis under `prefers-reduced-motion`
  • Relative timestamps through `arc-time-ago`, with the absolute date on hover
  • An `avatar` slot on each message for products that want faces; none are built in
  • RTL mirrors automatically: alignment is logical-properties only
  • Server-renders in full, pending dots included

Preview

Project "Neon Tides" opened — the assistant can see your arrangement. How do I loop the chorus while I try out lead takes? Drag the **loop brace** over bars 17-24, then: 1. Press L to switch looping on 2. Arm the lead track 3. Hit record — every pass lands on its own take lane Can it keep every take, or just the last one?

Usage

This component requires JavaScript. No pure HTML/CSS version is available. Use the Web Component directly or a framework wrapper.

<arc-conversation style="--conversation-height: 400px">
  <arc-message speaker="user" author="You" timestamp="2026-07-31T14:02:00Z">
    How do I loop the chorus while I try out lead takes?
  </arc-message>
  <arc-message speaker="assistant" author="daw[n]" markdown timestamp="2026-07-31T14:02:04Z">
    Drag the **loop brace** over bars 17-24, press L, then arm the
    lead track — every pass lands on its own take lane.
  </arc-message>
  <arc-message speaker="assistant" author="daw[n]" pending></arc-message>
</arc-conversation>

<script>
  // Streaming: fill the pending message as tokens arrive.
  const reply = document.querySelector('arc-message[pending]');
  function onToken(token) {
    reply.pending = false;
    reply.markdown = true;
    reply.textContent += token;
  }
</script>

API

autoScrollbooleantrue
Follow new content: when a message is added or grows while the reader is near the bottom, scroll to keep the latest visible. A reader who has scrolled up is never pulled back down. Defaults to true; set the property to false to leave scrolling entirely to the consumer.

Methods

scrollToEnd()
Scroll the transcript to its newest message.

Events

arc-scroll-awaydetail:{value: number}
Fired once when the reader scrolls up out of the near-bottom zone of the transcript. detail.value is the distance from the bottom in pixels.
arc-scroll-returndetail:{value: number}
Fired once when the reader comes back within the near-bottom zone. detail.value is the distance from the bottom in pixels.

Message

<arc-message>

One message in the transcript. The speaker attribute picks the voice (user, assistant, or system), author and timestamp fill the muted meta line, markdown renders the slotted text through the markdown renderer, and pending shows the typing indicator until a reply arrives.

authorstring''
Display name shown in the muted meta line above the bubble. Omit it and the meta line only appears when a timestamp is set.
timestampstring''
When the message was sent, as an ISO 8601 string. Rendered as house relative time ("3 minutes ago") through arc-time-ago, with the absolute date on its title.
speaker'user' | 'assistant' | 'system''user'
Whose message this is. "user" aligns to the inline end on an accent-tinted surface, "assistant" to the inline start on a neutral surface, and "system" runs centered and muted for notices in the transcript's own voice. An unrecognized value renders as "user".
pendingbooleanfalse
Renders the typing indicator (three pulsing dots) in place of the body while a reply is being produced. Under prefers-reduced-motion the dots give way to a static ellipsis.
markdownbooleanfalse
Render the slotted text through the house markdown renderer. The slot's text content is the source; it re-parses whenever the slot changes, so streaming into the slot streams through the renderer. When false, slotted content renders as-is.

See Also