Source Code

<div class="bscw-wrap">
  <div class="card bscw-window d-none" id="bscwWindow">
    <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center py-2">
      <span class="fw-bold small">Support Chat</span>
      <button type="button" class="btn-close btn-close-white" aria-label="Close" id="bscwClose"></button>
    </div>
    <div class="card-body bscw-body" id="bscwBody">
      <div class="bscw-msg bscw-bot">Hi there! How can we help you today?</div>
    </div>
    <div class="card-footer p-2">
      <form class="d-flex gap-2" id="bscwForm">
        <input type="text" class="form-control form-control-sm" id="bscwInput" placeholder="Type a message..." autocomplete="off">
        <button type="submit" class="btn btn-primary btn-sm">Send</button>
      </form>
    </div>
  </div>

  <button type="button" class="btn btn-primary rounded-circle bscw-launcher" id="bscwLauncher" aria-label="Open chat">
    &#128172;
  </button>
</div>

Bootstrap Floating Chat Widget — Free JS Snippet

Bootstrap Floating Chat Widget · Layouts · Plain HTML, CSS & JS · Live preview

What's included

Features

Fixed-position launcher and window pinned to the bottom-right corner at all scroll positions
Real Bootstrap card, card-header, and card-footer structure for the chat window
Distinct open/close controls: launcher toggles, header × button always closes
Simulated bot replies delayed via setTimeout for a realistic conversational feel
Cycling reply array so the bot never runs out of responses
Auto-scroll to the latest message after every user or bot message
Messages inserted with textContent to prevent HTML/script injection from typed input
Responsive max-width so the window never overflows a narrow mobile viewport

About this UI Snippet

Bootstrap Floating Chat Widget — HTML, CSS & JavaScript

Screenshot of the Bootstrap Floating Chat Widget snippet rendered live

A floating chat widget lives outside the normal document flow by design — the whole .bscw-wrap container is pinned with position: fixed; right: 20px; bottom: 20px and a z-index: 1080, deliberately set above Bootstrap's own default modal z-index tier so the widget stays clickable even on pages using Bootstrap modals or offcanvas panels elsewhere. The circular launcher button is a real Bootstrap btn btn-primary rounded-circle, and the chat window itself is a genuine Bootstrap card absolutely positioned at bottom: 72px; right: 0 relative to that fixed wrapper, so it always opens directly above the launcher regardless of scroll position, with max-width: calc(100vw - 40px) keeping it from overflowing the viewport on narrow phone screens.

Opening and closing is a single classList.toggle('d-none') call on #bscwWindow from the launcher's click handler, paired with a dedicated Bootstrap btn-close btn-close-white in the card header that only ever closes (never toggles) the window — two different controls with two clearly distinct behaviors instead of one ambiguous toggle button doing double duty. When the window opens, the input is explicitly focused and scrollToBottom() runs, so returning to an open conversation always lands the user at the most recent message and ready to type immediately.

Sending a message follows a deliberately realistic two-step flow: addMessage(text, 'user') appends a right-aligned blue .bscw-user bubble immediately using textContent (never innerHTML, so a typed message containing angle brackets can't be interpreted as markup), then a setTimeout of 900ms delays the bot's response before addMessage(reply, 'bot') appends a left-aligned gray .bscw-bot bubble. That artificial delay is intentional — an instant reply reads as obviously fake, while a short pause mimics the network or "typing" latency of a real chat backend. The bot cycles through a fixed botReplies array using replyIndex % botReplies.length, so it never runs out of responses no matter how many messages are sent, looping back to the first reply after the fourth.

The non-obvious detail this snippet gets right is auto-scroll: every call to addMessage() — for both user and bot messages — ends by setting body.scrollTop = body.scrollHeight, which is the standard way to pin a scrollable container to its bottom edge after content is appended. Without this, the message list would silently overflow its fixed height: 300px and new messages would append below the visible area, invisible until the user manually scrolled down — a bug that's easy to miss when testing with only one or two messages but becomes obvious the moment a conversation grows.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Ask an AI coding assistant like Claude to add a typing indicator (three animated dots) shown during the setTimeout delay before the bot reply appears, or to add an unread-message badge on the launcher when the window is closed. It's also worth asking it to persist chat history to localStorage across reloads.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a Bootstrap 5.3 floating chat widget using the real Bootstrap CDN framework (bootstrap.min.css and bootstrap.bundle.min.js), not custom CSS made to resemble Bootstrap.

Requirements:
- A fixed-position circular launcher button in the bottom-right corner of the viewport, and a real Bootstrap card styled as a chat window (header with a close button, scrollable message body, footer with a text input and send button) that toggles visibility when the launcher is clicked.
- Sending a message via the form must immediately append a right-aligned "user" message bubble, then after a short setTimeout delay append a left-aligned simulated "bot" reply bubble cycling through a small fixed array of canned responses.
- The message list must automatically scroll to the bottom every time a new message (user or bot) is appended, using scrollTop and scrollHeight.
- All message text must be inserted using textContent, not innerHTML, so typed input cannot inject HTML or scripts.
- The window must have a sensible max-width so it does not overflow the viewport on a narrow mobile screen.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Load the snippetOnly a circular blue launcher button with a speech-bubble icon is visible in the bottom-right corner; the chat window is hidden.
  2. 2
    Click the launcherA chat window slides into view above the launcher, showing a header, one greeting message from the bot, and a message input focused and ready to type.
  3. 3
    Type a message and press SendYour message appears immediately as a blue bubble on the right side of the message list, and the list scrolls to show it.
  4. 4
    Wait about a secondA gray bot reply bubble appears on the left side automatically, and the message list auto-scrolls to keep it visible.
  5. 5
    Click the × in the headerThe chat window closes completely; clicking the launcher again reopens it with the full conversation history still intact.

Real-world uses

Common Use Cases

CHAT
Customer support widgets
A live-chat-style support launcher for a marketing or SaaS site, often placed alongside a cookie consent banner in the page's fixed UI layer.
AI chatbot demo interfaces
A ready-made front end for prototyping a chatbot before wiring the setTimeout-based reply logic to a real language model API call.
Learning fixed-position UI and auto-scroll
A clear example of stacking a fixed launcher and an absolutely positioned panel together, plus the scrollTop/scrollHeight auto-scroll pattern used in any chat or log UI.
Lead-capture and pre-sales chat
Combine with a notification center dropdown so returning visitors see both new messages and site notifications from one corner of the UI.
In-app help and onboarding assistants
Provide contextual help inside a dashboard or app shell, similar in placement to a filter sidebar offcanvas that stays available without leaving the page.

Got questions?

Frequently Asked Questions

No — this is a front-end demo cycling through a fixed array of canned replies with a setTimeout delay to simulate a real conversation. Replace the setTimeout callback with a real fetch call to your chat or AI backend for production use.

Both work — the launcher toggles the window open and closed, and the header × button is provided as a more discoverable, conventional close control right where users expect it, matching common chat widget UX patterns.

Yes — track an isOpen boolean and a messages array in component state (React useState, Vue ref, Angular class fields), render messages with .map()/*ngFor*, and replace the direct scrollTop DOM write with a ref-based effect that runs after each new message renders.

Yes — every appended message triggers body.scrollTop = body.scrollHeight, which pins the scrollable message container to its bottom edge, so the newest message (user or bot) is always visible without manual scrolling.

Yes — addMessage() uses element.textContent to insert both user and bot text, which always renders as plain text rather than being parsed as HTML, preventing a typed message from injecting markup or scripts into the page.

The wrapper uses z-index: 1080, intentionally higher than Bootstrap 5.3's default modal (1055) and offcanvas (1045) layers, so the chat launcher and window remain visible and clickable above other Bootstrap components rather than being hidden behind them.

Yes — replace the card, btn, and rounded-circle classes with Tailwind utilities for the fixed launcher and panel, and keep addMessage(), the setTimeout reply logic, and the scrollTop auto-scroll exactly as written, since none of that JavaScript reads Bootstrap-specific classes.