aiux
PatternsPatternsCoursesCoursesNewsNewsResourcesResources
Overview

Foundations

  • What Is Conversational UI? (And What It Isn't)
  • Anatomy of a Chat Interface

Building

  • Building Message Bubbles in React
  • Typing Indicators & Streaming Responses
  • Suggested Prompts & Conversation Starters

Advanced Patterns

  • Managing Conversation Context
  • Error Handling & Fallback Design
  • Voice Interface Design Patterns

Ship It

  • Accessibility in Conversational UI
  • Putting It All Together - Architecture Checklist
  • Agentic Conversational UI - When AI Takes Actions
  1. Guides
  2. /
  3. Build a Conversational UI
  4. /
  5. Building Message Bubbles in React
BuildingLesson 3 of 11

Building Message Bubbles in React

4 min readConversational UI for DesignersUpdated Apr 2, 2026

A message bubble in React is a styled div inside a scrollable list, rendered from a { role, content, timestamp } data shape. This lesson builds one from scratch with auto-scroll, avatars, and status states — the foundation under every chat UI.

Data Model

Start with a clean message type:

Message type definition
interface Message {
  id: string;
  role: 'user' | 'assistant';
  content: string;
  timestamp: Date;
  status?: 'sending' | 'sent' | 'error';
}

Keep the model simple. You can extend it later with attachments, metadata, or citations, but the core is: who said what, and when.

Message Component

Each message is a flex container with conditional alignment:

ChatMessage component
  • max-w-[75%] prevents full-width blobs that are hard to read
  • rounded-2xl gives the modern bubble shape
  • whitespace-pre-wrap preserves AI formatting and line breaks

Auto-Scrolling

Chat interfaces must auto-scroll to the latest message - but only when the user is already at the bottom. If they've scrolled up to read history, don't yank them down.

Smart auto-scroll hook
const messagesEndRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null);

const isNearBottom = () => {
  const el = containerRef.current;
  if (!el) return true;
  return el.scrollHeight - el.scrollTop - el.clientHeight < 100;
};

useEffect(() => {
  if (isNearBottom()) {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }
}, [messages]);

The < 100 threshold gives a small buffer - users scrolled up slightly still get auto-scroll.

Test auto-scroll on mobile especially. Touch scrolling has momentum - users may still be "scrolling" when a new message arrives. Use `behavior: 'smooth'` to avoid jarring jumps.

← Previous LessonAnatomy of a Chat InterfaceNext Lesson →Typing Indicators & Streaming Responses
← Back to Build a Conversational UI overview

On this page

  • Data Model
  • Message Component
  • Auto-Scrolling

aiux

AI UX patterns from shipped products. Demos, code, and real examples.

Have an idea? Share feedback

Get daily AI UX news

Resources

  • All Patterns
  • Browse Categories
  • Contribute
  • AI Interaction Toolkit
  • Agent Readability Audit
  • Newsletter
  • Documentation
  • Figma Make Prompts
  • Designer Guides
  • All Resources →

Company

  • About Us
  • Privacy Policy
  • Terms of Service
  • Contact

Links

  • Portfolio
  • GitHub
  • LinkedIn
  • More Resources

Copyright © 2026 All Rights Reserved.