Source Code

<div name="lcl-page" class="lcl-page">
  <main class="lcl-content"><p>&#8593; Page content above the footer</p></main>
  <footer class="lcl">
    <div class="lcl-inner">
      <div class="lcl-col">
        <p class="lcl-brand">Northline Studio</p>
        <p class="lcl-copy">&copy; 2026 Northline Studio Inc.</p>
      </div>
      <ul class="lcl-links">
        <li><a href="#">Docs</a></li>
        <li><a href="#">Pricing</a></li>
        <li><a href="#">Status</a></li>
        <li><a href="#">Privacy</a></li>
      </ul>
      <button class="lcl-launcher" id="lclLauncher">
        <span class="lcl-avatars">
          <span class="lcl-avatar" style="background:#f59e0b">M</span>
          <span class="lcl-avatar" style="background:#6366f1">J</span>
        </span>
        <span class="lcl-launcher-text">
          <b>Chat with us</b>
          <small><span class="lcl-dot"></span> Online &mdash; avg reply 2 min</small>
        </span>
      </button>
    </div>
  </footer>

  <div class="lcl-panel" id="lclPanel" hidden>
    <div class="lcl-panel-head">
      <div>
        <b>Support</b>
        <small><span class="lcl-dot"></span> Online now</small>
      </div>
      <button class="lcl-close" id="lclClose" aria-label="Close chat">&times;</button>
    </div>
    <div class="lcl-panel-body" id="lclBody">
      <div class="lcl-msg lcl-msg-them">Hi! I'm Jordan from support. What can I help you with today?</div>
    </div>
    <div class="lcl-quick" id="lclQuick">
      <button class="lcl-chip" data-q="pricing">Pricing question</button>
      <button class="lcl-chip" data-q="bug">Report a bug</button>
      <button class="lcl-chip" data-q="human">Talk to a human</button>
    </div>
    <form class="lcl-form" id="lclForm">
      <input class="lcl-input" id="lclInput" type="text" placeholder="Type a message..." autocomplete="off">
      <button class="lcl-send" type="submit" aria-label="Send">&#10148;</button>
    </form>
  </div>
</div>

Live Chat Launcher Footer Bar — Free HTML CSS JS Snippet

Live Chat Launcher Footer Bar · Footers · Plain HTML, CSS & JS · Live preview

What's included

Features

Footer-embedded launcher with overlapping agent avatars and a pulsing online-status dot
Working chat panel toggled with panel.hidden, animated in with a rise keyframe
Real two-way message thread with distinct sent/received bubble styling
Quick-reply chips that route to canned answers keyed by a data attribute
Simulated typing indicator with a realistic delay before each reply
Free-text input handled through the same reply pipeline as the quick chips
Auto-scroll to the newest message on every send
Responsive panel that goes full-width on small screens
Zero dependencies, vanilla JavaScript only

About this UI Snippet

Live Chat Launcher Footer — Support Bar with Working Chat Panel

Screenshot of the Live Chat Launcher Footer Bar snippet rendered live

Many sites bury live chat behind a small floating bubble in the corner, easy to miss on a first visit. This snippet instead puts the launcher directly in the footer as a real support bar — stacked agent avatars, an online status dot with a pulse animation, and an average-reply-time label — so the offer to chat is visible the moment a visitor scrolls to the bottom of any page, alongside the usual footer links and copyright line.

A launcher that reads as "real people," not a generic icon

.lcl-avatars overlaps two colored initial-avatars with a negative margin, the same visual shorthand used by team-presence indicators across support tools — it signals there are specific humans behind the chat, not a bot-only widget. The pulsing green .lcl-dot next to "Online" uses a CSS box-shadow keyframe animation to draw the eye without JavaScript, and the average-reply-time text sets an honest expectation before the visitor even clicks.

A functioning chat panel, not a static mockup

Clicking the launcher toggles a fixed-position #lclPanel in the bottom-right corner via panel.hidden = !panel.hidden, animated in with a small lclRise keyframe. Inside, addMessage(text, who) appends a real message bubble styled by sender (lcl-msg-me vs lcl-msg-them) and scrolls the body to the newest message — this is a working two-way conversation thread, not a screenshot standing in for one.

Quick-reply chips that route to canned answers

Three suggestion chips ("Pricing question," "Report a bug," "Talk to a human") sit above the input row. Clicking one posts it as an outgoing message and looks up a matching canned response in the replies object keyed by data-q, so a visitor can get a useful first answer without typing anything — a real pattern used by production support-chat products to deflect the most common questions before a human ever needs to look.

A typing indicator with a realistic delay

Before any reply appears, showTyping() inserts a three-dot bouncing .lcl-typing element and reply() waits roughly 900ms before removing it and inserting the actual message. This mirrors the perceived-latency pattern real chat products use — an instant reply feels robotic and untrustworthy, while a short typing pause before the response reads as a person actually composing an answer.

Free-text fallback

Typing anything into the input and submitting the form appends it as an outgoing message and triggers a generic acknowledgement reply through the same reply() path used by the quick chips, so the panel handles both guided and open-ended conversations with one shared code path.

Wiring it to a real support backend

Replace the replies lookup and the generic fallback text with calls to your actual support platform's API (Intercom, Zendesk, a custom WebSocket channel), and swap the simulated setTimeout typing delay for a real "agent is typing" event pushed from the backend once connected.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than tracing the message and typing-indicator flow by hand, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how showTyping() and reply() coordinate to make a canned response feel like a person typing rather than an instant scripted reply. The same assistant can help you optimize it, for instance asking whether the fixed 900ms delay should vary randomly for a more natural feel. It is also useful for extending the footer: ask it to wire the replies object to a real support API or WebSocket connection, add file/screenshot attachment support to the message form, or persist the conversation in localStorage so it survives a page reload. Treat the code less like a finished artifact and more like a starting point for a conversation.

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 footer "live chat launcher" bar in plain HTML, CSS, and JavaScript that opens a working floating chat panel, no chat SDK or library.

Requirements:
- A dark footer bar with brand and link columns plus a launcher button showing two overlapping colored avatar circles, an "Online" label with a pulsing status dot (CSS animation, no JS), and an average-reply-time line.
- Clicking the launcher toggles a fixed-position chat panel in a bottom corner of the screen (hidden attribute, not display none) with a small rise-in entrance animation, containing a header with a close button, a scrollable message thread starting with one greeting message, a row of quick-reply suggestion chips, and a text input with a send button.
- Clicking a quick-reply chip must add it as an outgoing message bubble, then show a three-dot bouncing typing indicator, then after a short delay replace the indicator with a canned reply looked up from a JavaScript object keyed by a data attribute on the chip.
- Submitting the text input must add the typed text as an outgoing message bubble the same way, then trigger the same typing-indicator-then-reply sequence with a generic acknowledgement message, reusing the same code path as the quick-reply chips rather than duplicating the logic.
- The message thread must auto-scroll to the newest message every time one is added, and closing the panel must not clear the conversation — reopening it must show the same messages exactly as they were left.

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
    Paste HTML, CSS, and JSA dark footer bar renders with agent avatars, an online status pulse, and a Chat with us launcher.
  2. 2
    Click the launcherA chat panel rises in the bottom-right corner with a greeting message already visible.
  3. 3
    Click a quick-reply chipIt posts as your message, shows a typing indicator, then a canned reply appears after a short delay.
  4. 4
    Type your own messageSubmit the form to see it added to the thread with the same typing-then-reply sequence.
  5. 5
    Close and reopenThe close button hides the panel; clicking the launcher again reopens it without losing the conversation.
  6. 6
    Wire it to a real backendReplace the replies object and setTimeout delay with calls to your support platform’s live chat API.

Real-world uses

Common Use Cases

SaaS marketing and pricing pages
Surface a real support option at the exact moment a visitor has scrolled through the whole page and still has questions.
E-commerce checkout support
Quick-reply chips like "Report a bug" or "Talk to a human" let shoppers get unstuck without leaving the checkout flow.
Documentation and developer portals
Pair with a Sitemap Directory Footer so both self-serve links and live human help are available in the same footer region.
Teaching a minimal chat-UI state machine
A compact reference for message rendering, a typing-indicator delay pattern, and canned-reply routing without any chat SDK.
Related: Sticky CTA Footer
See the Sticky CTA Footer for a related footers pattern worth pairing with this one.
Related: Footer Live Status Indicator
See the Footer Live Status Indicator for a related footers pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

No — the replies object contains canned demo text keyed by each quick-reply chip, and the free-text input triggers a generic acknowledgement. In production, replace both with calls to a real support backend such as Intercom, Zendesk, or a custom WebSocket channel.

showTyping() inserts a three-dot bouncing element into the message thread before the reply text is known to the user, and reply() waits about 900ms via setTimeout before removing it and inserting the actual message — simulating the natural pause of a person composing a response.

Add a new button with a data-q attribute inside #lclQuick, and add a matching key/value pair to the replies object in the JS panel with the canned answer text.

Yes — closing only sets panel.hidden to true, which hides it visually without clearing the message thread in #lclBody, so reopening shows the same conversation exactly where it left off.

Yes — change the right and bottom values on .lcl-panel to left and top (or any combination) to reposition it; the rise-in animation works from any corner.

Yes. Model the thread as an array of {text, who} objects in state, append to it on send, and drive a separate isTyping boolean to show or hide the typing indicator before appending the actual reply after your own delay or real API response.