๐Ÿš€ How to Build an AI Chatbot Using HTML, CSS, and JavaScript with Gemini API & Emoji Picker
June 30, 20255 min read

๐Ÿš€ How to Build an AI Chatbot Using HTML, CSS, and JavaScript with Gemini API & Emoji Picker

Web developmentJavaScriptCSS3JavaScript Projects
share this article on

In this tutorial, weโ€™ll walk through the process of creating a fully functional AI chatbot that can handle user messages, display AI-generated responses using the Gemini API, and even support emoji input. This chatbot is perfect for websites that want to engage users, offer support, or deliver personalized experiences.

๐Ÿ’ก Where Can You Use This Chatbot?

This chatbot can be integrated into:

โœจ Features of the Chatbot

  1. AI Integration with Gemini API from Google
  2. Emoji picker using emoji-picker-element
  3. Typing indicator while bot is responding
  4. Chat popup toggle with a floating bot icon
  5. Responsive design for web and mobile

๐Ÿงฑ Project Structure

/chatbot-project
  โ”œโ”€โ”€ index.html
  โ”œโ”€โ”€ styles.css
  โ”œโ”€โ”€ script.js
  โ””โ”€โ”€ /asset/image/chatbot.png

๐Ÿ–ผ๏ธ HTML Code: Chatbot Layout

This code defines the structure of the chatbot, including the popup, message window, and input field.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AI Chatbot</title>
  <!-- CSS Stylesheet -->
  <link rel="stylesheet" href="styles.css">
  <!-- Emoji Picker Element Script Path -->
  <script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@^1/index.js"></script>
  
</head>
<body>
  <!-- Chatbot Trigger Button -->
  <div class="chatbot-trigger" id="chatbotTrigger">
    <!-- Chatbot Trigger Toggle Image -->
    <img src="./asset/image/chatbot.png" alt="Chatbot">
  </div>

  <!-- Chatbot Popup -->
  <div class="chatbot-popup" id="chatbotPopup">
    <header class="chatbot-header">
      <div class="bot-info">
        <!-- Header Chatbot Image -->
        <img src="./asset/image/chatbot.png" alt="Bot Icon" class="header-bot-icon">
        <span>AI Chatbot</span>
      </div>
      <button id="closeBtn">&times;</button>
    </header>
    <div class="chat-window" id="chatWindow">
      <div class="message bot">
        <!-- Chatbot Image for Bot Icon Image -->
        <img src="./asset/image/chatbot.png" alt="Bot Icon" class="message-icon">
        <div class="message-content">Welcome to AI chatbot!</div>
      </div>
    </div>
    <div class="chat-input-section">
      <!-- User Input Textarea -->
      <textarea id="messageInput" placeholder="Type a message..."></textarea>
      <!-- Emoji Picker Button -->
        <button id="emojiPickerBtn">๐Ÿ˜Š</button>
        
      </div>
      <!-- Emoji Picker Element -->
      <emoji-picker></emoji-picker>
    </div>
  </div>   
   <!-- Javascript Code Script Path -->
    <script defer src="script.js"></script>
</body>
</html>

๐ŸŽจ CSS Code: Styling the Chatbot

Hereโ€™s the styling for the chatbot trigger, popup, messages, input area, and the emoji picker.

/* General Styles */
body {
  font-family: Arial, sans-serif;
  background-color: #161a20;
  color: #fff;
  margin: 0;
  position: relative;
}

/* Chatbot Trigger Button */
.chatbot-trigger {
  position: fixed;
  bottom: 120px;
  right: 20px;
  width: 60px;
  height: 60px;
  background-color: #007bff;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
}

.chatbot-trigger .bot-icon {
  width: 40px;
  height: 40px;
}

#chatbotTrigger img {
  width: 60px;
  height: 60px;
  border-radius: 50%;
}

/* Chatbot Popup */
.chatbot-popup {
  position: fixed;
  bottom: 150px;
  right: 20px;
  width: 400px;
  height: 500px;
  background-color: #1e252b;
  border-radius: 8px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
  display: none;
  flex-direction: column;
  overflow: hidden;
}

/* Chatbot Header */
.chatbot-header {
  background-color: #7c59f7;
  padding: 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: white;
}

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

.chatbot-header .header-bot-icon {
  width: 30px;
  height: 30px;
  border-radius: 50%;
}

.chatbot-header button {
  background: none;
  border: none;
  color: white;
  font-size: 18px;
  cursor: pointer;
} 

.chatbot-header button:hover {
  color: #fff;
}

/* Chat Window */
.chat-window {
  flex: 1;
  padding: 10px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background-color: #fff;
}

.message {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.message.bot .message-icon {
  width: 30px;
  height: 30px;
  border-radius: 50%;
}

.message .message-content {
  background-color: #6a4bd9;
  padding: 10px;
  border-radius: 5px;
  max-width: 100%;
  color: white;
}

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

.message.user .message-content {
  background-color: #007bff;
}

/* Typing Indicator */
.message.bot.typing-indicator .message-content {
  display: flex;
  gap: 5px;
}

.typing-indicator .dot {
  width: 8px;
  height: 8px;
  background-color: #007bff;
  border-radius: 50%;
  animation: blink 1.4s infinite;
}

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

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

/* Typing Indicator Blink Animation */

@keyframes blink {
  0%, 80%, 100% {
    opacity: 0;
  }
  40% {
    opacity: 1;
  }
}

/* Input Section */
.chat-input-section {
  display: flex;
  gap: 5px;
  padding: 10px;
  background-color: #272d34;
  align-items: center;
}

textarea {
  flex: 1;
  resize: none;
  padding: 5px;
  border: none;
  border-radius: 4px;
  outline: none;
}

.action-buttons {
  display: flex;
  gap: 5px;
}

button {
  background: none;
  border: none;
  color: white;
  font-size: 20px;
  cursor: pointer;
}

button:hover {
  color: #007bff;
}

/* Emoji Picker styles */

emoji-picker {
  display: none;
  position: absolute;
  bottom: 70px;
  right: 40px;
  width: 350px;
  max-height: 300px;
  z-index: 1000;
}

๐Ÿง  JavaScript: Bot Logic and API Integration

This file manages chatbot behavior, emoji picker, typing indicators, and Gemini API communication.

// Elements
const chatbotTrigger = document.getElementById('chatbotTrigger');
const chatbotPopup = document.getElementById('chatbotPopup');
const closeBtn = document.getElementById('closeBtn');
const chatWindow = document.getElementById('chatWindow');
const messageInput = document.getElementById('messageInput');
const emojiPickerBtn = document.getElementById('emojiPickerBtn');
const emojiPicker = document.querySelector('emoji-picker');

let emojiPickerVisible = false; // Track visibility of the emoji picker

// Show and Hide Chatbot
chatbotTrigger.addEventListener('click', () => {
  chatbotPopup.style.display = 'flex';
  chatbotTrigger.style.display = 'none';
});

closeBtn.addEventListener('click', () => {
  chatbotPopup.style.display = 'none';
  chatbotTrigger.style.display = 'flex';
});

// Append User and Bot Messages
function appendMessage(content, sender = 'user', isHTML = false) {
  const messageDiv = document.createElement('div');
  messageDiv.classList.add('message', sender);
  const messageContent = document.createElement('div');
  messageContent.classList.add('message-content');
  if (isHTML) {
    messageContent.innerHTML = content;
  } else {
    messageContent.textContent = content;
  }
  messageDiv.appendChild(messageContent);

  if (sender === 'bot') {
    const botIcon = document.createElement('img');
    botIcon.src = './asset/image/chatbot.png';
    botIcon.alt = 'Bot Icon';
    botIcon.classList.add('message-icon');
    messageDiv.prepend(botIcon);
  }

  chatWindow.appendChild(messageDiv);
  chatWindow.scrollTop = chatWindow.scrollHeight;
  return messageDiv;
}

// Typing Indicator
function showTypingIndicator() {
  const typingDiv = appendMessage('', 'bot', true);
  typingDiv.classList.add('typing-indicator');
  typingDiv.innerHTML = `
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
  `;
  return typingDiv;
}

function removeTypingIndicator(typingDiv) {
  if (typingDiv) typingDiv.remove();
}

// Handle Send Message
async function handleSendMessage() {
  const message = messageInput.value.trim();
  if (message) {
    appendMessage(message, 'user');
    messageInput.value = '';

    // Show typing indicator
    const typingDiv = showTypingIndicator();

    try {
      // Replace YOUR_API_KEY with generated Gemini API key value
      const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=YOUR_API_KEY', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          contents: [{ parts: [{ text: message }] }]
        })
      });

      if (!response.ok) {
        throw new Error(`Error: ${response.statusText}`);
      }

      const data = await response.json();
      if (data && data.candidates && data.candidates.length > 0) {
        const botReply = data.candidates[0].content.parts[0].text;
        removeTypingIndicator(typingDiv);
        appendMessage(botReply, 'bot');
      } else {
        throw new Error('No valid response from API');
      }
    } catch (error) {
      removeTypingIndicator(typingDiv);
      appendMessage('Oops, something went wrong. Please try again.', 'bot');
      console.error('Gemini API Error:', error);
    }
  }
}

// Handle Enter Key to Send
messageInput.addEventListener('keydown', (e) => {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    handleSendMessage();
  }
});

// Emoji Picker Toggle
emojiPickerBtn.addEventListener('click', (event) => {
  event.stopPropagation();
  emojiPickerVisible = !emojiPickerVisible;
  emojiPicker.style.display = emojiPickerVisible ? 'block' : 'none';
});

// Close Emoji Picker when clicking outside
document.addEventListener('click', (event) => {
  if (!emojiPicker.contains(event.target) && event.target !== emojiPickerBtn) {
    emojiPicker.style.display = 'none';
    emojiPickerVisible = false;
  }
});

// Append Emoji to Input Field
emojiPicker.addEventListener('emoji-click', (event) => {
  messageInput.value += event.detail.unicode;
});

๐Ÿ”‘ Final Notes

Happy coding!


Back to Articles