What are we working on today? Press send to start a new
conversation
ET
Thinking...
Demo is read only. Press send to send messages.
Bubble
Each message is an <li class="bubble">. When the
<li> holds more than the message, like an avatar,
put the bubble on a <div> inside it instead. Add
me for the current user's messages. They move to the
other side and use the primary color. Give the chat
role="log" and a label, so new messages are announced as
they arrive.
Other messages have no background, which suits long answers from an
assistant. Add secondary to put them in a gray bubble,
like in a chat between people.
Which fruit has the most vitamin C?
Per 100 grams, a few stand out:
Guava, about 230 mg
Kiwi, about 90 mg
Orange, about 50 mg
Didn't expect guava!
Most people don't. It has about four times as much as an orange.
<div class="chat" role="log" aria-label="Conversation"> <ul> <li class="bubble me">Which fruit has the most vitamin C?</li> <li class="bubble ghost"> <p>Per 100 grams, a few stand out:</p> <ul> <li><strong>Guava</strong>, about 230 mg</li> <li><strong>Kiwi</strong>, about 90 mg</li> <li><strong>Orange</strong>, about 50 mg</li> </ul> </li> <li class="bubble me">Didn't expect guava!</li> <li class="bubble"> Most people don't. It has about four times as much as an orange. </li> </ul></div>
Avatar
Put an Avatar first in the
<li> to show who sent the message. It sits next to
the last bubble, so one <li> can hold several
bubbles from the same sender. On me messages it moves to
the other side.
Give it role="img" and the sender's name in
aria-label, so screen readers read the name instead of
the initials. For an image avatar, put the name in alt.
AL
Did you see the new designs?
I think the colors are much better now.
JR
Just looked. I love the new buttons.
<div class="chat" role="log" aria-label="Conversation"> <ul> <li> <span class="avatar" role="img" aria-label="Alex Lee">AL</span> <div class="bubble">Did you see the new designs?</div> <div class="bubble">I think the colors are much better now.</div> </li> <li> <span class="avatar" role="img" aria-label="You">JR</span> <div class="bubble me">Just looked. I love the new buttons.</div> </li> </ul></div>
Pending
Show that a reply is on its way with a
Shimmer in the
<li>, in place of the bubble. It gets the bubble's
padding, so its text lines up with the reply. Swap it for a bubble
once the reply arrives. If the reply streams in, set
aria-busy="true" on the bubble until it is done, so
screen readers read it once instead of word by word.
What's the tallest mountain in Europe?
Thinking...
<div class="chat" role="log" aria-label="Conversation"> <ul> <li class="bubble me">What's the tallest mountain in Europe?</li> <li> <p class="shimmer">Thinking...</p> </li> </ul></div>
Jump to latest
Put a <button class="jump"> last in the chat. It
sticks to the bottom while there are newer messages below, and hides
once the chat is scrolled to the end. Scroll up in the example to see
it. Give the chat a height so it scrolls.
Showing and hiding needs no JavaScript. Scrolling down on click does.
Move focus to the chat on click too, since the button hides once the
chat is scrolled down. In browsers without scroll-state queries the
button is always visible.
Can you help me plan a trip to Lisbon?
Sure. How many days do you have?
Four, in May.
Four days is a good length. Spend the first in Alfama and Baixa, the
second in Belém, and take a day trip to Sintra on the third.
And the last day?
Keep it slow. Walk along the river to LX Factory, and end the day at a
miradouro for the sunset.
<div class="chat" role="log" aria-label="Conversation" tabindex="0" style="height: 16rem"> <ul> <li class="bubble me">Can you help me plan a trip to Lisbon?</li> <li class="bubble">Sure. How many days do you have?</li> <li class="bubble me">Four, in May.</li> <li class="bubble"> Four days is a good length. Spend the first in Alfama and Baixa, the second in Belém, and take a day trip to Sintra on the third. </li> <li class="bubble me">And the last day?</li> <li class="bubble"> Keep it slow. Walk along the river to LX Factory, and end the day at a miradouro for the sunset. </li> </ul> <button class="jump secondary square round" aria-label="Jump to latest" onclick=" const chat = this.parentElement; chat.focus(); chat.scrollTo({ top: chat.scrollHeight, behavior: 'smooth' }); " > <svg>...</svg> </button></div>
API reference
Type
Classes / attributes
What it does
Chat
.chat
The scrolling container. Holds a ul of bubbles and an optional jump button
Bubble
.bubble
On an li, or a div inside one. One message, with no background
Avatar
.avatar
First in an li. Shows who sent the bubbles, next to the last one
Sender
.me
On a bubble. Moves it to the other side and uses the primary color
Style
.secondary
On a bubble. A gray background
Jump to latest
.jump
On a button last in .chat. Shows while there are newer messages below