Skip to content

Chat

The shell for a chatbot or assistant: a header, a scrolling conversation, suggested prompts and a composer. It has no backend; your code answers an event.

CSS
css/components/chat.css
JS
js/components/chat.js

01 — Example

In a page

Ask anything, or press a suggestion. This demo answers with a canned reply (data-chat-demo).

Assistant

Online
  1. Assistant

    Hi. Ask me about your photos.

Answers can be wrong. Check anything important.

02 — Connect it

Answer the event

respond() takes a string, { html }, or a promise of either. A rejected promise shows the error with a Retry button.

JS
chat.addEventListener('jewel:chatsend', (e) => {
  e.detail.respond(
    fetch('/ask', { method: 'POST', body: e.detail.text }).then((r) => r.text())
  );
});

03 — Behavior

Script

NameDetail
KeysEnter sends, Shift+Enter is a new line. On touch screens Enter is always a new line.
Prompts[data-chat-prompt] buttons send their own text and hide once the chat starts.
Placement.chat--floating fixes it in the bottom-right corner (full screen on phones). It also fits in a sheet.
el.jewelChat.add("user" | "bot", text), .typing(true), .clear().

04 — Usage

Use it for

  • An assistant that answers questions about the person’s own content.
  • Two or three suggested prompts that show what it can do.
  • A note that answers can be wrong.

Avoid

  • Pretending a person is answering.
  • Long-form writing. Answers should be short and link onward.

05 — Accessibility

Notes

  • The conversation is a role="log", so new replies are announced.
  • The composer has a visually hidden label; the send button has an aria-label.

06 — Without Jewel’s JS

What the script does

The script adds each message to the log, shows a typing indicator, clears the composer and fires jewel:chatsend for your code to answer. The CSS reads only the markup below, so a framework can render the conversation from its own state and leave out chat.js and data-component.

StateSet thisNotes
Message<li class="chat__msg chat__msg--user"> or chat__msg--bot, holding p.chat__author and div.chat__textIn ol.chat__log. CSS hides the user’s author line (“You”) visually.
TypingA last <li class="chat__msg chat__msg--bot" aria-label="Assistant is typing"> holding <span class="chat__typing" aria-hidden="true"> with three empty <span>sUse the bot’s name in the label. Remove it when the reply arrives.
Waiting for a replyaria-busy="true" and disabled on .chat__sendClear both when the reply or the error is in.
Failed replychat__msg--error on the bot messageShows its text in the error color. Put a Retry button inside.
Startedis-started on .chatHides .chat__prompts after the first message.
Scrollable logtabindex="0" on .chat__logSo keyboard users can scroll it.

Events and keyboard

  • Enter sends and Shift+Enter is a new line. Skip this during IME composition (isComposing) and on touch screens (pointer: coarse), where Enter is always a new line.
  • After each message, scroll the log to the bottom, smoothly unless reduced motion is on.
  • Clear the composer after sending. The textarea grows with field-sizing: content; where that isn’t supported, the script sets its height from scrollHeight as people type.
  • jewel:chatsend doesn’t fire without the script. Send the text to your backend yourself.