5 Pure CSS3 with JSPublished 2026-10-04Free · no sign-up
Eight chat interface pieces: a two-person conversation, grouped messages with avatars and read receipts, a typing indicator, an AI assistant reply with a code block, emoji reactions, a working support widget, image and file messages and date dividers.
A two-person conversation with incoming bubbles on the left and outgoing on the right, each with a tail made by flattening one corner. The thread is an ordered list, and each message includes the sender name in hidden text for screen readers.
View code
<ol class="ch">
<li class="in"><span class="sr">Support said: </span>Hi! How can I help with your order?</li>
<li class="out"><span class="sr">You said: </span>It says delivered but I have not received it.</li>
<li class="in"><span class="sr">Support said: </span>Sorry about that. Let me check with the courier now.</li>
</ol>
Messages with an avatar, the sender name, a timestamp in a time element and read receipts on sent messages. Consecutive messages from the same person are grouped so the avatar appears once, which keeps long threads easier to scan.
View code
<div class="cm">
<div class="grp in"><span class="av" aria-hidden="true">LA</span><div><p class="who">Lina <time datetime="2026-10-04T09:12">9:12</time></p><p class="b">Are we still on for Friday?</p><p class="b">I can bring the samples.</p></div></div>
<div class="grp out"><div><p class="b">Yes, see you at 10.</p><p class="rcpt"><time datetime="2026-10-04T09:14">9:14</time> · Read</p></div></div>
</div>
The three bouncing dots that show the other person is typing, inside an incoming bubble. Each dot uses the same animation with a staggered delay, a hidden text says Lina is typing, and the bounce becomes a gentle fade with reduced motion.
View code
<div class="typ"><span class="sr">Lina is typing</span><i></i><i></i><i></i></div>
A chat layout for an AI assistant: the person's message in a bubble and the assistant's reply as full-width text with a code block and a copy button. Long replies read better without a bubble, and the code scrolls sideways instead of breaking the layout.
View code
<div class="ai">
<p class="me">How do I centre a div?</p>
<div class="bot"><p>Use grid on the parent:</p><pre tabindex="0"><code>.parent {
display: grid;
place-items: center;
}</code></pre><button>Copy code</button></div>
</div>
A message bubble with emoji reaction pills underneath, each showing a count. Reactions are buttons with aria-pressed, so you can toggle your own; the accessible name spells out the reaction and count, such as Thumbs up, 3.
View code
<div class="rx">
<p class="bub">New autumn colours are live on the shop! 🎉</p>
<div class="pills">
<button aria-pressed="true" aria-label="Thumbs up, 3 reactions, including yours">👍 <b>3</b></button>
<button aria-pressed="false" aria-label="Heart, 5 reactions">❤️ <b>5</b></button>
<button aria-label="Add reaction">+</button>
</div>
</div>
document.querySelectorAll('.pills [aria-pressed]').forEach(b => b.addEventListener('click', () => {
const on = b.getAttribute('aria-pressed') !== 'true', n = b.querySelector('b');
n.textContent = +n.textContent + (on ? 1 : -1); b.setAttribute('aria-pressed', String(on));
}));
06. Support Chat Widget
WidgetSupport
A floating support chat panel with a header, a short message history and a composer. The panel is a region named Support chat, the composer has a real label, and sending appends the message to the list and clears the field.
View code
<section class="cw" aria-label="Support chat">
<header><b>Clayworks support</b><small>Usually replies in minutes</small></header>
<ol id="cw-l"><li class="in">Hi! Ask us anything about your order.</li></ol>
<form id="cw-f"><label for="cw-i" class="sr">Message</label><input id="cw-i" placeholder="Type a message" autocomplete="off"><button>Send</button></form>
</section>
document.getElementById('cw-f').addEventListener('submit', e => {
e.preventDefault();
const i = document.getElementById('cw-i'); if (!i.value.trim()) return;
const li = document.createElement('li'); li.className = 'out'; li.textContent = i.value;
const l = document.getElementById('cw-l'); l.appendChild(li); l.scrollTop = l.scrollHeight; i.value = '';
});
07. Image and File Messages
AttachmentsChat
Messages that carry attachments: a photo with a caption and a file card with its name, size and a download link. The photo has alt text, the file link names the file, and the bubbles keep the same tail style as text messages.
View code
<div class="att">
<figure class="out"><div class="ph" role="img" aria-label="Photo of a blue glazed bowl"></div><figcaption>The new glaze!</figcaption></figure>
<div class="in file"><span aria-hidden="true">PDF</span><div><b>invoice-1048.pdf</b><small>124 KB</small></div><a href="#" aria-label="Download invoice-1048.pdf">Download</a></div>
</div>
Thread furniture: a centred date divider and a system notice such as Sam joined the group, between ordinary messages. The divider is a heading for navigation, the lines are pseudo-elements, and the notice is visually distinct from people's messages.
View code
<div class="sys">
<p class="m in">See you all tomorrow.</p>
<h3 class="day">Today</h3>
<p class="note">Sam joined the group</p>
<p class="m in">Morning everyone!</p>
</div>
The speech-bubble tail is just one corner with a smaller radius, such as border-bottom-left-radius: 4px. Incoming bubbles align left and outgoing ones right with align-self.
Who said what
Visually the side shows the sender, but screen readers need words. Add hidden text like You said, or show names, and keep messages in an ordered list in time order.
New messages
In a live chat, put the message list in a region that announces new incoming messages politely, and never steal focus from the composer when a message arrives.
Long replies
Assistant replies with code or lists read better as full-width text without a bubble, with code blocks that scroll sideways instead of stretching the layout.
Frequently asked questions
Which demos need JavaScript?
The AI copy button, reactions and the support widget.
How do I animate the typing dots?
One keyframe with staggered animation-delay per dot, as in the typing demo, with a fade for reduced motion.
Can I use these in a real chat app?
Yes. Connect the composer to your messaging backend and append messages as list items.