v1.10.2
Theme

Chat

Chat uses the current DuskMoonUI design: rounded user bubbles, unboxed agent answers, native work disclosures, a waiting-message tray, and a compact composer. Styles come from @duskmoon-dev/core; local adjustments connect those styles across Shadow DOM and slots.

Installation

npm install @duskmoon-dev/el-chat

Usage

import '@duskmoon-dev/el-chat/register';
<el-dm-chat
  agent
  align="start"
  avatar="AI"
  author="Assistant"
  time="Just now"
  status="sent"
  content="I can help with **markdown** content."
>
</el-dm-chat>

Live Demo

Full Conversation

Current Agent Design

Reviewed the message layout, queue tray, and composer controls.Agent content and activity use DuskMoonUI styles.
Complete reply

Use agent for an unboxed assistant answer. Put activity in an el-dm-chat-work assigned to slot="work"; closing it leaves the answer visible. Existing bubble messages remain available by omitting agent.

<el-dm-chat agent author="Assistant" content="The final **answer** stays visible.">
  <el-dm-chat-work slot="work" summary="Worked · 2 tool calls">
    <el-dm-chat-reasoning summary="Thinking">Reviewing the request.</el-dm-chat-reasoning>
    <el-dm-chat-tool name="search" status="success"></el-dm-chat-tool>
  </el-dm-chat-work>
</el-dm-chat>
<el-dm-chat align="end" color="primary" collapsible content="A long user message…"></el-dm-chat>

collapsible limits a bubble to six rendered lines. Longer content gets a native Show more / Show less button, with aria-controls and aria-expanded. The element rechecks wrapped text when its content or width changes; short messages need no toggle. expanded controls the open state. Agent answers remain uncollapsed.

The example starts with an active reply and two waiting messages. Steer inserts a waiting message into the current conversation without starting another reply. Complete reply advances the example queue. Queue state and dispatch belong to the application.

Scroll-Driven Transcript

Wrap messages in el-dm-chat-scroll and assign each assistant message a unique timeline from 1 through 24. User messages remain in the transcript but do not receive indicators. The rail uses DuskMoonUI Scroll-Driven Animations when supported; its buttons remain a functional fallback and always scroll only the transcript panel.

Give the wrapper an explicit height so its body can overflow.

<el-dm-chat-scroll style="height: 22rem">
  <el-dm-chat agent timeline="1" author="Assistant" content="First assistant reply"></el-dm-chat>
  <el-dm-chat align="end" author="You" content="A user message"></el-dm-chat>
  <el-dm-chat agent timeline="2" author="Assistant" content="Second assistant reply"></el-dm-chat>
</el-dm-chat-scroll>

Properties

el-dm-chat and el-dm-chat-bubble

Property Type Default Description
agent boolean false Unboxed assistant layout (el-dm-chat only)
collapsible boolean false Collapse bubbles exceeding six rendered lines
expanded boolean false Reveal the complete collapsible bubble
align 'start' | 'end' 'start' Message alignment
color 'primary' | 'secondary' | 'tertiary' | 'info' | 'success' | 'warning' | 'error' - Bubble color
size 'xs' | 'sm' | 'md' | 'lg' - Bubble size
variant 'tonal' | 'filled' 'tonal' Bubble visual style
streaming boolean false Shows a streaming caret
avatar string - Avatar text fallback
author string - Header author text
time string - Footer timestamp
status string - Footer delivery status
actions string - Comma-separated icon actions
content string - Markdown content to render
timeline 1 through 24 - Assistant indicator mapping (el-dm-chat only)

el-dm-chat-scroll

Property Type Default Description
label string 'Conversation' Accessible transcript-region label
indicator-label string 'Assistant replies' Indicator navigation and button prefix

Timeline values must be unique. When duplicate values are supplied, the last eligible assistant message wins. The generated navigate event is cancelable and contains { timeline, index, target }.

el-dm-chat-input

Property Type Default Description
name string '' Form field name
value string '' Markdown input value
placeholder string 'Message the agent…' Input placeholder
disabled boolean false Disables the input and send
readonly boolean false Makes the input read-only
send-label string 'Send' Send button label
clear-on-send boolean false Clears text and local files after sending
busy boolean false Label the primary action Queue and enable draft steering
color semantic color or ghost - DuskMoonUI composer color
auto-grow boolean false Grow the editor with content up to its maximum height

Local attachments are exposed directly on the chat input. getFiles() returns a snapshot, and clearFiles() removes all locally attached files.

Set --dm-chat-editor-min-height on the chat input to size both the outer editor and its nested markdown editor. The compact default is 3rem. With auto-grow, the editor expands as text is entered, then its write area scrolls at --dm-chat-editor-max-height (default 24rem).

el-dm-chat-work

Property Type Default Description
summary string 'Work' Activity summary; counts and labels come from the application
open boolean false Open the native work disclosure

el-dm-chat-queue

Property Type Default Description
items ChatQueueItem[] [] Ordered queue items; set the property or a JSON attribute
label string 'Queued messages' Accessible queue name

Each item has { id, content, active?, attachment?, attachmentAlt? }. Keep id stable and mark the next item active. attachment is an optional thumbnail URL; provide descriptive attachmentAlt text. Empty queues are hidden. Row controls emit steer and remove with { item, index }; the element leaves the array under application control.

<el-dm-chat-input busy color="ghost" auto-grow>
  <el-dm-chat-queue slot="queue" label="Waiting messages"></el-dm-chat-queue>
</el-dm-chat-input>
queue.items = [{ id: 'draft-1', content: 'Check accessibility too.', active: true }];
queue.addEventListener('steer', ({ detail: { item } }) => {
  addUserMessageToCurrentConversation(item.content);
  queue.items = queue.items.filter((queued) => queued.id !== item.id);
});

The composer emits send for its primary action; the application can send immediately or queue while busy. steer on the composer carries { value, files } for the current draft. Enter submits, Shift+Enter preserves a newline, and Ctrl/Cmd+Enter steers while busy (or sends while idle). IME confirmation never submits. Blank drafts require an attachment. Both draft events are cancelable: call preventDefault() to retain the draft and attachments, including when awaiting an asynchronous admission result. Clear accepted asynchronous drafts through setValue() and clearFiles() after acknowledgment, preserving any later edits. focus() focuses the editor.

el-dm-chat-reasoning

Property Type Default Description
summary string 'Reasoning' Default summary label
open boolean false Opens the details by default

el-dm-chat-tool

Property Type Default Description
name string - Tool name
status 'pending' | 'running' | 'success' | 'error' 'pending' Tool call status
open boolean false Opens the details by default

Bubble Variants

Bubble Colors

<el-dm-chat-bubble color="primary" content="Primary **markdown** response"></el-dm-chat-bubble>
<el-dm-chat-bubble color="success" content="Success response"></el-dm-chat-bubble>
<el-dm-chat-bubble align="end" color="info" variant="filled" content="Filled info response">
</el-dm-chat-bubble>

Markdown Content

Use the content attribute or property for markdown-rendered message bodies.

Markdown Message

<el-dm-chat
  agent
  avatar="AI"
  author="Assistant"
  content="Rendered **markdown** with `inline code`."
></el-dm-chat>

Chat Input

Markdown Chat Input

<el-dm-chat-input placeholder="Message the agent…" send-label="Send" clear-on-send>
</el-dm-chat-input>

<script>
  document.querySelector('el-dm-chat-input').addEventListener('send', (event) => {
    const { value, files } = event.detail;
    // Encode or upload the File objects before forwarding a serializable payload.
    console.log(value, files);
  });
</script>

For a compact composer that starts around two to three lines:

<el-dm-chat-input
  auto-grow
  style="--dm-chat-editor-min-height: 4.5rem; --dm-chat-editor-max-height: 16rem"
></el-dm-chat-input>

Status and Quick Actions

Message Status and Actions

<el-dm-chat
  agent
  avatar="AI"
  author="Assistant"
  time="12:06"
  status="streaming"
  actions="Stop, Copy"
  content="I am writing a response and exposing icon quick actions."
></el-dm-chat>

Reasoning

Place reasoning and tool elements inside a message with the reasoning and tools slots. They render before the final markdown answer, and a streaming caret stays attached to that final answer.

Reasoning Inside a Message

Checked the current DuskMoonUI chat contract before updating the custom element.

npm info @duskmoon-dev/core version1.20.6
Chat tests passed
<el-dm-chat agent streaming content="The final **answer** streams here.">
  <el-dm-chat-reasoning slot="reasoning" summary="Reasoning" open>
    Checked package metadata before making the change.
    <el-dm-chat-tool slot="tools" name="package-search" status="success"></el-dm-chat-tool>
  </el-dm-chat-reasoning>
  <el-dm-chat-tool slot="tools" name="build" status="success"></el-dm-chat-tool>
</el-dm-chat>

Tool Calls

Tool Call Status

rg “chat” packages/docsdocs build completed
<el-dm-chat-tool name="search" status="running" open>
  <code slot="call">rg "chat" packages/docs</code>
</el-dm-chat-tool>

Slots

Element Slot Description
el-dm-chat-scroll default Direct el-dm-chat transcript rows
el-dm-chat default Final markdown bubble content
el-dm-chat work Activity disclosure before the final answer
el-dm-chat reasoning Reasoning shown before the final answer
el-dm-chat tool Single direct tool call
el-dm-chat tools Direct tool calls
el-dm-chat avatar Avatar shown beside the message
el-dm-chat header Metadata above the bubble
el-dm-chat footer Metadata below the bubble
el-dm-chat actions Custom quick action controls
el-dm-chat-bubble reasoning Reasoning shown before the final answer
el-dm-chat-bubble tool Single direct tool call
el-dm-chat-bubble tools Direct tool calls
el-dm-chat-input queue Waiting queue attached above the composer
el-dm-chat-work default Work records, reasoning, and tool calls
el-dm-chat-work summary Custom native disclosure summary
el-dm-chat-reasoning default Reasoning body
el-dm-chat-reasoning summary Custom summary content
el-dm-chat-reasoning tool Single tool call in reasoning
el-dm-chat-reasoning tools Tool calls in reasoning
el-dm-chat-tool default Extra tool body content
el-dm-chat-tool name Custom tool header name
el-dm-chat-tool call Tool call input
el-dm-chat-tool result Tool result output

CSS Parts

Part Description
scroll Scrollable transcript region
track Sticky indicator rail
indicator Generated assistant-reply button
body Transcript, work, or reasoning body
chat Chat row container
avatar Avatar wrapper
header Header metadata
bubble Message bubble
bubble-content Final answer inside the bubble
toggle Show more / Show less button
footer Footer metadata
status Message status
actions Quick actions wrapper
action Generated icon action button
content Agent answer or rendered markdown
input Chat input wrapper
composer Core composer surface
editor Markdown input element
send Send button
steer Composer Steer button
queue Waiting-message tray
list Ordered queue list
item Queued message row
work Native work disclosure
summary Work or reasoning summary
reasoning Reasoning details container
tools Reasoning tool-call wrapper
tool Tool details container
typing Typing indicator

Events

Element Event Detail
el-dm-chat-scroll navigate { timeline, index, target }
el-dm-chat quick-action { action, label }
el-dm-chat-input send { value, files }
el-dm-chat-input steer { value, files }
el-dm-chat-queue steer, remove { item, index }

Cancel navigate with event.preventDefault() to replace the built-in in-panel scrolling.