Chat Interface

Conversational UI.

Assistant

Can you summarise this document?

Here is a three-line summary of the key points.

Assistant is typing

html

<section class="chat-interface" style="--accent:#D9C8F0;">
  <header class="chat-interface__header">
    <span class="chat-interface__avatar" aria-hidden="true"></span>
    <span class="chat-interface__name">Assistant</span>
  </header>
  <div class="chat-interface__messages">
    <p class="chat-interface__msg chat-interface__msg--user">Can you summarise this document?</p>
    <p class="chat-interface__msg chat-interface__msg--assistant">Here is a three-line summary of the key points.</p>
    
    <div class="chat-interface__typing" role="status" aria-live="polite">
      <span class="chat-interface__typing-dots" aria-hidden="true"><span></span><span></span><span></span></span>
      <span class="chat-interface__srtext">Assistant is typing</span>
    </div>
    
  </div>
  <div class="chat-interface__composer">
    <input class="chat-interface__input" type="text" placeholder="Ask a question…" aria-label="Message" />
    <button class="chat-interface__send" type="button">Send</button>
  </div>
</section>
<style>
.chat-interface { font: 14px/1.5 system-ui, sans-serif; color: #241430; background: #FAF7F2; max-width: 360px; padding: 14px; border-radius: 14px; border: 1px solid #24143014; box-sizing: border-box; }
.chat-interface__header { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.chat-interface__avatar { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); flex: none; }
.chat-interface__name { font-weight: 600; font-size: 13px; }
.chat-interface__messages { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.chat-interface__msg { margin: 0; padding: 8px 12px; border-radius: 12px; max-width: 82%; font-size: 13.5px; }
.chat-interface__msg--user { align-self: flex-end; background: var(--accent); color: #241430; }
.chat-interface__msg--assistant { align-self: flex-start; background: #24143010; }
.chat-interface__typing { display: flex; align-items: center; gap: 6px; align-self: flex-start; padding: 8px 12px; }
.chat-interface__typing-dots { display: inline-flex; gap: 3px; }
.chat-interface__typing-dots span { width: 5px; height: 5px; border-radius: 50%; background: #24143066; display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
.chat-interface__typing-dots span { animation: chat-interface-bounce .2s ease-in-out infinite; }
.chat-interface__typing-dots span:nth-child(2) { animation-delay: .03s; }
.chat-interface__typing-dots span:nth-child(3) { animation-delay: .06s; }
}
@keyframes chat-interface-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-3px); opacity: 1; } }
.chat-interface__srtext { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.chat-interface__composer { display: flex; gap: 8px; }
.chat-interface__input { flex: 1; padding: 8px 10px; border: 1.5px solid #24143026; border-radius: 8px; font: inherit; color: #241430; background: #fff; box-sizing: border-box; }
.chat-interface__input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.chat-interface__send { background: var(--accent); color: #241430; border: none; padding: 8px 14px; border-radius: 8px; font: 600 13px system-ui, sans-serif; cursor: pointer; }
.chat-interface__send:focus-visible { outline: 2px solid #241430; outline-offset: 2px; }
</style>

tailwind

<section class="font-sans text-sm leading-relaxed text-[#241430] bg-[#FAF7F2] max-w-[360px] p-3.5 rounded-2xl border border-[#24143014] box-border" style="--accent:#D9C8F0;">
  <header class="flex items-center gap-2 mb-2.5">
    <span class="w-[22px] h-[22px] rounded-full flex-none" style="background:var(--accent)" aria-hidden="true"></span>
    <span class="font-semibold text-[13px]">Assistant</span>
  </header>
  <div class="flex flex-col gap-2 mb-2.5">
    <p class="m-0 self-end px-3 py-2 rounded-xl max-w-[82%] text-[13.5px]" style="background:var(--accent);color:#241430;">Can you summarise this document?</p>
    <p class="m-0 self-start px-3 py-2 rounded-xl max-w-[82%] text-[13.5px] bg-[#24143010]">Here is a three-line summary of the key points.</p>
    
    <div class="chat-interface-tw__typing flex items-center gap-1.5 self-start px-3 py-2" role="status" aria-live="polite">
      <span class="inline-flex gap-[3px]" aria-hidden="true"><span></span><span></span><span></span></span>
      <span class="sr-only">Assistant is typing</span>
    </div>
    
  </div>
  <div class="flex gap-2">
    <input class="flex-1 px-2.5 py-2 border-[1.5px] border-[#24143026] rounded-lg bg-white text-[#241430] box-border" type="text" placeholder="Ask a question…" aria-label="Message" />
    <button class="px-3.5 py-2 rounded-lg text-[13px] font-semibold border-none cursor-pointer" style="background:var(--accent);color:#241430;" type="button">Send</button>
  </div>
</section>
<style>
.chat-interface-tw__typing span span { width: 5px; height: 5px; border-radius: 50%; background: #24143066; display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
.chat-interface-tw__typing span span { animation: chat-interface-tw-bounce .2s ease-in-out infinite; }
.chat-interface-tw__typing span span:nth-child(2) { animation-delay: .03s; }
.chat-interface-tw__typing span span:nth-child(3) { animation-delay: .06s; }
}
@keyframes chat-interface-tw-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-3px); opacity: 1; } }
</style>

react

export function ChatInterface({
  placeholder = "Ask a question…",
  assistantName = "Assistant",
  accent = "#D9C8F0",
  showTyping = true,
}) {
  return (
    <section style={{ fontFamily: "system-ui, sans-serif", fontSize: 14, lineHeight: 1.5, color: "#241430",
      background: "#FAF7F2", maxWidth: 360, padding: 14, borderRadius: 14, border: "1px solid #24143014", boxSizing: "border-box" }}>
      <header style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
        <span aria-hidden="true" style={{ width: 22, height: 22, borderRadius: "50%", background: accent, flex: "none" }} />
        <span style={{ fontWeight: 600, fontSize: 13 }}>{assistantName}</span>
      </header>
      <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 10 }}>
        <p style={{ margin: 0, alignSelf: "flex-end", padding: "8px 12px", borderRadius: 12, maxWidth: "82%",
          fontSize: 13.5, background: accent, color: "#241430" }}>Can you summarise this document?</p>
        <p style={{ margin: 0, alignSelf: "flex-start", padding: "8px 12px", borderRadius: 12, maxWidth: "82%",
          fontSize: 13.5, background: "#24143010" }}>Here is a three-line summary of the key points.</p>
        {showTyping && (
          <div role="status" aria-live="polite" style={{ display: "flex", alignItems: "center", gap: 6, alignSelf: "flex-start", padding: "8px 12px" }}>
            <span aria-hidden="true" style={{ display: "inline-flex", gap: 3 }}>
              <span className="ci-dot ci-dot--1" style={{ width: 5, height: 5, borderRadius: "50%", background: "#24143066" }} />
              <span className="ci-dot ci-dot--2" style={{ width: 5, height: 5, borderRadius: "50%", background: "#24143066" }} />
              <span className="ci-dot ci-dot--3" style={{ width: 5, height: 5, borderRadius: "50%", background: "#24143066" }} />
            </span>
            <span style={{ position: "absolute", width: 1, height: 1, overflow: "hidden", clip: "rect(0 0 0 0)" }}>{assistantName} is typing</span>
          </div>
        )}
      </div>
      <div style={{ display: "flex", gap: 8 }}>
        <input type="text" placeholder={placeholder} aria-label="Message" style={{ flex: 1, padding: "8px 10px",
          border: "1.5px solid #24143026", borderRadius: 8, font: "inherit", color: "#241430", background: "#fff", boxSizing: "border-box" }} />
        <button type="button" style={{ background: accent, color: "#241430", border: "none", padding: "8px 14px",
          borderRadius: 8, fontSize: 13, fontWeight: 600, cursor: "pointer" }}>Send</button>
      </div>
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          .ci-dot--1 { animation: chat-interface-react-bounce 1s ease-in-out infinite; }
          .ci-dot--2 { animation: chat-interface-react-bounce 1s ease-in-out .15s infinite; }
          .ci-dot--3 { animation: chat-interface-react-bounce 1s ease-in-out .3s infinite; }
          @keyframes chat-interface-react-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-3px); opacity: 1; } }
        }
      `}</style>
    </section>
  );
}