
๐ How to Build an AI Chatbot Using HTML, CSS, and JavaScript with Gemini API & Emoji Picker
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:
- Customer support portals
- E-commerce websites (for helping users find products)
- Educational sites (for FAQs or tutoring bots)
- SaaS dashboards (as a virtual assistant)
- Personal blogs or portfolios (as a unique interactive feature)
โจ Features of the Chatbot
- AI Integration with Gemini API from Google
- Emoji picker using emoji-picker-element
- Typing indicator while bot is responding
- Chat popup toggle with a floating bot icon
- 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">×</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
- Make sure to replace YOUR_API_KEY with a valid Gemini API Key from Google.
- You can easily extend this bot with voice input, image responses, or file uploads.
- The bot is responsive and lightweightโgreat for any kind of web project.
Happy coding!