Chatbot Bootstrap 5

🏷️ Extraits & Composants HTML 📅 08/04/2026 13:00:00 👤 Mezgani Said
Bootstrap 5 Chatbot List Bootstrap 5 Design Template Html Integration List Ai

Chatbot Bootstrap 5 optimisées pour la visualisation et l'interaction. Composants modernes et responsive.

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8" />
  <meta name="copyright" content="MEZGANI Said" />
  <meta name="author" content="AngularForAll" />
  <meta name="robots" content="noindex, nofollow" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Snippet Chatboot Bootstrap 5 2026 23040041 | AngularForAll</title>
<!-- Bootstrap 5 + Icons -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
  <style>
    body {
      background: #f4f7fc;
      min-height: 100vh;
      font-family: 'Segoe UI', system-ui, sans-serif;
    }

    /* ----- CHATBOT WIDGET (flottant) ----- */
    .chatbot-widget {
      position: fixed;
      bottom: 24px;
      right: 24px;
      z-index: 1055;
      display: flex;
      flex-direction: column;
      align-items: flex-end;
    }

    /* fenêtre de chat */
    .chatbot-window {
      width: 340px;
      max-width: calc(100vw - 32px);
      background: white;
      border-radius: 24px;
      box-shadow: 0 12px 28px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.08);
      overflow: hidden;
      margin-bottom: 16px;
      transition: opacity 0.2s, transform 0.2s;
      border: 1px solid rgba(0, 0, 0, 0.05);
    }

    .chatbot-window.d-none {
      display: none !important;
    }

    /* en-tête */
    .chatbot-header {
      background: linear-gradient(145deg, #0d6efd, #0b5ed7);
      color: white;
      padding: 16px 18px;
      display: flex;
      align-items: center;
      justify-content: space-between;
    }

    .chatbot-header-left {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .chatbot-avatar {
      width: 40px;
      height: 40px;
      background: white;
      border-radius: 40px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #0d6efd;
      font-weight: bold;
      font-size: 20px;
      box-shadow: 0 2px 6px rgba(0,0,0,0.15);
    }

    .chatbot-title h6 {
      margin: 0;
      font-weight: 600;
      letter-spacing: -0.2px;
    }

    .chatbot-title small {
      opacity: 0.85;
      font-size: 12px;
    }

    .btn-close-chat {
      background: rgba(255,255,255,0.2);
      border: none;
      color: white;
      width: 32px;
      height: 32px;
      border-radius: 32px;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: 0.15s;
    }

    .btn-close-chat:hover {
      background: rgba(255,255,255,0.3);
    }

    /* corps / messages */
    .chatbot-body {
      height: 360px;
      overflow-y: auto;
      padding: 18px 16px;
      background: #f9fafc;
      display: flex;
      flex-direction: column;
      gap: 12px;
    }

    .message {
      display: flex;
      max-width: 85%;
    }

    .message.bot {
      align-self: flex-start;
    }

    .message.user {
      align-self: flex-end;
    }

    .message-content {
      padding: 12px 16px;
      border-radius: 20px;
      font-size: 14px;
      line-height: 1.45;
      word-break: break-word;
    }

    .bot .message-content {
      background: white;
      border: 1px solid #e9ecef;
      border-bottom-left-radius: 6px;
      box-shadow: 0 1px 3px rgba(0,0,0,0.02);
    }

    .user .message-content {
      background: #0d6efd;
      color: white;
      border-bottom-right-radius: 6px;
    }

    .typing-indicator {
      display: flex;
      gap: 5px;
      padding: 8px 14px;
      background: white;
      border-radius: 20px;
      border-bottom-left-radius: 6px;
      width: fit-content;
      border: 1px solid #e9ecef;
    }

    .typing-dot {
      width: 8px;
      height: 8px;
      background: #adb5bd;
      border-radius: 50%;
      animation: typingPulse 1.2s infinite ease-in-out;
    }

    .typing-dot:nth-child(2) { animation-delay: 0.2s; }
    .typing-dot:nth-child(3) { animation-delay: 0.4s; }

    @keyframes typingPulse {
      0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
      30% { transform: translateY(-6px); opacity: 1; }
    }

    /* zone de saisie */
    .chatbot-footer {
      background: white;
      padding: 12px 16px;
      border-top: 1px solid #eef2f6;
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .chatbot-footer .form-control {
      border-radius: 40px;
      background: #f2f5f9;
      border: 1px solid #e0e7ef;
      padding: 10px 16px;
      font-size: 14px;
    }

    .chatbot-footer .form-control:focus {
      background: white;
      box-shadow: 0 0 0 3px rgba(13,110,253,0.15);
      border-color: #0d6efd;
    }

    .btn-send {
      background: #0d6efd;
      color: white;
      border-radius: 40px;
      width: 44px;
      height: 44px;
      display: flex;
      align-items: center;
      justify-content: center;
      border: none;
      transition: 0.15s;
    }

    .btn-send:hover {
      background: #0b5ed7;
      transform: scale(1.02);
    }

    .btn-send i {
      font-size: 18px;
    }

    /* bouton toggle principal (flottant) */
    .chatbot-toggle-btn {
      width: 60px;
      height: 60px;
      border-radius: 60px;
      background: #0d6efd;
      color: white;
      border: none;
      box-shadow: 0 8px 16px rgba(13, 110, 253, 0.25);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 28px;
      transition: all 0.2s;
      border: 2px solid rgba(255,255,255,0.3);
    }

    .chatbot-toggle-btn:hover {
      background: #0b5ed7;
      transform: scale(1.05);
      box-shadow: 0 10px 20px rgba(13, 110, 253, 0.35);
    }

    .chatbot-toggle-btn i {
      transition: transform 0.2s;
    }

    /* petites animations */
    .message {
      animation: fadeInUp 0.25s ease;
    }

    @keyframes fadeInUp {
      from { opacity: 0; transform: translateY(8px); }
      to { opacity: 1; transform: translateY(0); }
    }

    /* scroll personnalisé */
    .chatbot-body::-webkit-scrollbar { width: 5px; }
    .chatbot-body::-webkit-scrollbar-track { background: transparent; }
    .chatbot-body::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }

    /* petit badge non lu (optionnel) */
    .unread-badge {
      position: absolute;
      top: -4px;
      right: -4px;
      background: #dc3545;
      color: white;
      border-radius: 30px;
      padding: 2px 6px;
      font-size: 11px;
      font-weight: bold;
      border: 2px solid white;
    }

    /* responsive */
    @media (max-width: 480px) {
      .chatbot-window { width: calc(100vw - 32px); }
    }
  </style>
</head>
<body>

<!-- Contenu de démonstration (optionnel) -->
<div class="container py-5">
  <div class="row justify-content-center">
    <div class="col-lg-8 text-center">
      <h1 class="display-5 fw-semibold mb-3">🤖 Assistant Virtuel</h1>
      <p class="lead text-secondary">Cliquez sur l'icône en bas à droite pour discuter avec notre chatbot Bootstrap 5.</p>
      <div class="mt-5 p-4 bg-white rounded-4 shadow-sm">
        <i class="bi bi-chat-dots fs-1 text-primary"></i>
        <p class="mt-3">Posez une question sur nos services, les tarifs ou le support.</p>
      </div>
    </div>
  </div>
</div>

<!-- ========== WIDGET CHATBOT ========== -->
<div class="chatbot-widget">
  <!-- Fenêtre de chat (cachée par défaut) -->
  <div class="chatbot-window d-none" id="chatWindow">
    <div class="chatbot-header">
      <div class="chatbot-header-left">
        <div class="chatbot-avatar">
          <i class="bi bi-robot"></i>
        </div>
        <div class="chatbot-title">
          <h6>SupportBot</h6>
          <small><i class="bi bi-circle-fill text-success me-1" style="font-size: 8px;"></i>En ligne · répond en ~1min</small>
        </div>
      </div>
      <button class="btn-close-chat" id="closeChatBtn" aria-label="Fermer">
        <i class="bi bi-x-lg"></i>
      </button>
    </div>

    <!-- Zone de messages -->
    <div class="chatbot-body" id="chatBody">
      <!-- Message initial du bot -->
      <div class="message bot">
        <div class="message-content">
          👋 Bonjour ! Je suis l'assistant virtuel. Comment puis-je vous aider aujourd'hui ?
        </div>
      </div>
      <!-- les autres messages seront injectés ici -->
    </div>

    <!-- Pied avec input -->
    <div class="chatbot-footer">
      <input type="text" class="form-control" id="chatInput" placeholder="Écrivez votre message..." autocomplete="off">
      <button class="btn-send" id="sendMessageBtn">
        <i class="bi bi-send-fill"></i>
      </button>
    </div>
  </div>

  <!-- Bouton toggle (ouvrir/fermer) -->
  <button class="chatbot-toggle-btn" id="toggleChatBtn">
    <i class="bi bi-chat-dots-fill"></i>
  </button>
</div>

<!-- Bootstrap JS + Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
  (function() {
    'use strict';

    // ---------- ÉLÉMENTS DOM ----------
    const chatWindow = document.getElementById('chatWindow');
    const toggleBtn = document.getElementById('toggleChatBtn');
    const closeBtn = document.getElementById('closeChatBtn');
    const chatBody = document.getElementById('chatBody');
    const chatInput = document.getElementById('chatInput');
    const sendBtn = document.getElementById('sendMessageBtn');

    // Icône du bouton toggle
    const toggleIcon = toggleBtn.querySelector('i');

    // ---------- FONCTIONS UTILITAIRES ----------

    // Ouvre la fenêtre de chat
    function openChat() {
      chatWindow.classList.remove('d-none');
      toggleIcon.classList.remove('bi-chat-dots-fill');
      toggleIcon.classList.add('bi-x-lg');
      // focus sur l'input
      setTimeout(() => chatInput.focus(), 50);
    }

    // Ferme la fenêtre
    function closeChat() {
      chatWindow.classList.add('d-none');
      toggleIcon.classList.remove('bi-x-lg');
      toggleIcon.classList.add('bi-chat-dots-fill');
    }

    // Bascule ouverture/fermeture
    function toggleChat() {
      if (chatWindow.classList.contains('d-none')) {
        openChat();
      } else {
        closeChat();
      }
    }

    // Scroll automatique vers le bas
    function scrollToBottom() {
      chatBody.scrollTop = chatBody.scrollHeight;
    }

    // Crée un message utilisateur
    function addUserMessage(text) {
      const messageDiv = document.createElement('div');
      messageDiv.className = 'message user';
      messageDiv.innerHTML = `<div class="message-content">${escapeHtml(text)}</div>`;
      chatBody.appendChild(messageDiv);
      scrollToBottom();
    }

    // Crée un message bot (texte simple)
    function addBotMessage(text) {
      const messageDiv = document.createElement('div');
      messageDiv.className = 'message bot';
      messageDiv.innerHTML = `<div class="message-content">${escapeHtml(text)}</div>`;
      chatBody.appendChild(messageDiv);
      scrollToBottom();
    }

    // Ajoute l'indicateur "typing..." et retourne l'élément pour le supprimer plus tard
    function addTypingIndicator() {
      const typingDiv = document.createElement('div');
      typingDiv.className = 'message bot';
      typingDiv.id = 'typingIndicator';
      typingDiv.innerHTML = `
        <div class="typing-indicator">
          <span class="typing-dot"></span>
          <span class="typing-dot"></span>
          <span class="typing-dot"></span>
        </div>
      `;
      chatBody.appendChild(typingDiv);
      scrollToBottom();
      return typingDiv;
    }

    function removeTypingIndicator() {
      const indicator = document.getElementById('typingIndicator');
      if (indicator) indicator.remove();
    }

    // Échappement basique pour éviter injection HTML
    function escapeHtml(text) {
      const div = document.createElement('div');
      div.textContent = text;
      return div.innerHTML;
    }

    // ---------- SIMULATION DE RÉPONSE BOT (logique simple) ----------
    function getBotResponse(userMessage) {
      const msg = userMessage.toLowerCase().trim();
      
      // Réponses prédéfinies basiques
      if (msg.includes('bonjour') || msg.includes('salut') || msg.includes('hello')) {
        return "Bonjour ! 😊 Comment puis-je vous aider ?";
      } else if (msg.includes('prix') || msg.includes('tarif') || msg.includes('coût')) {
        return "Nos tarifs varient selon les services. Le forfait de base commence à 29€/mois. Souhaitez-vous plus de détails ?";
      } else if (msg.includes('horaire') || msg.includes('ouverture')) {
        return "Notre équipe est disponible du lundi au vendredi, de 9h à 18h. Le support par chat est ouvert 24/7.";
      } else if (msg.includes('contact') || msg.includes('téléphone') || msg.includes('email')) {
        return "📞 Vous pouvez nous joindre au +33 1 23 45 67 89 ou par email à support@exemple.fr";
      } else if (msg.includes('merci')) {
        return "Avec plaisir ! N'hésitez pas si vous avez d'autres questions. 🌟";
      } else if (msg.includes('aide') || msg.includes('help')) {
        return "Je peux vous renseigner sur : tarifs, horaires, contact, ou assistance technique. Dites-moi ce dont vous avez besoin.";
      } else if (msg.includes('tech') || msg.includes('bug') || msg.includes('problème')) {
        return "Je suis désolé que vous rencontriez un souci. Pouvez-vous décrire le problème plus précisément ? Je vais vous guider.";
      } else {
        return "Intéressant ! Je suis un chatbot de démonstration. Pour le moment, je peux répondre à des questions sur les tarifs, horaires, contact ou assistance. Dites-m'en plus 😊";
      }
    }

    // Simulation asynchrone : réponse après un délai
    function simulateBotReply(userText) {
      // Afficher l'indicateur de saisie
      const typingEl = addTypingIndicator();

      // Délai aléatoire réaliste
      const delay = Math.floor(Math.random() * 900) + 800; // 800-1700ms

      setTimeout(() => {
        removeTypingIndicator();
        const response = getBotResponse(userText);
        addBotMessage(response);
      }, delay);
    }

    // ---------- GESTION ENVOI MESSAGE ----------
    function handleSendMessage() {
      const text = chatInput.value.trim();
      if (text === '') return;

      // Ajouter le message utilisateur
      addUserMessage(text);
      
      // Effacer l'input
      chatInput.value = '';
      
      // Simuler la réponse du bot
      simulateBotReply(text);
    }

    // ---------- ÉVÉNEMENTS ----------
    toggleBtn.addEventListener('click', toggleChat);
    closeBtn.addEventListener('click', closeChat);

    sendBtn.addEventListener('click', handleSendMessage);

    chatInput.addEventListener('keypress', (e) => {
      if (e.key === 'Enter') {
        e.preventDefault();
        handleSendMessage();
      }
    });

    // Option : clic extérieur pour fermer ? (non, on garde simple)
    // Empêche la fermeture involontaire, mais on peut ajouter échap
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && !chatWindow.classList.contains('d-none')) {
        closeChat();
      }
    });

    // Si on veut un petit "ping" de notification (badge non lu) après premier message?
    // Mais non nécessaire ici. On garde la version épurée.

    // Petit bonus : si l'utilisateur ouvre le chat, on scroll en bas
    const observer = new MutationObserver(() => {
      if (!chatWindow.classList.contains('d-none')) {
        scrollToBottom();
      }
    });
    observer.observe(chatWindow, { attributes: true, attributeFilter: ['class'] });

  })();
</script>

<!-- petite note : la démo utilise Bootstrap Icons, tout est inclus -->
</body>
</html>

Ouvrir cet aperçu dans un nouvel onglet du navigateur

🔗 Ouvrir dans le navigateur