In today’s world, AI-generated images are becoming more popular, allowing anyone to turn simple text prompts into stunning visuals. Now, imagine building your very own AI Image Generator that creates stunning images based on what users input, all with the power of the free Hugging Face API. And the best part? You can make it happen using just HTML, CSS, and JavaScript. Sounds exciting, right?
In this blog post, I’ll guide you through building an AI Image Generator using HTML, CSS, and JavaScript. This tool allows users to generate AI images based on a prompt, selected model, number of images, and aspect ratio. It also includes a download option for saving the generated images and supports both light and dark modes.
By the end of this project, you’ll not only have a fully functional tool that generates amazing images from text prompts, but you’ll also gain hands-on experience with API integration, data handling, DOM manipulation, and crafting a sleek, user-friendly design.
Video Tutorial of AI Image Generator in HTML & JavaScript
If you prefer learning through video, check out the YouTube tutorial linked above. It provides a detailed walkthrough of every line of code, with clear explanations and helpful comments. For those who prefer written instructions, keep reading as we break down the steps to build the AI Image Generator from scratch.
Steps to Create AI Image Generator HTML CSS & JavaScript
Follow these simple steps to build your AI Image Generator using HTML, CSS, and JavaScript:
- Create a new folder and name it, e.g., ai-image-generator.
- Inside this folder, create the following files:
index.html
,style.css
, andscript.js
.
In the index.html
file, set up the basic structure for the ai image generator. Use semantic elements like <header>
, <button>
, <option>
, and <form>
for a clean and accessible layout. Include an external Font Awesome link to display icons and load external CSS and JavaScript files.
<!DOCTYPE html> <!-- Coding By CodingNepal - youtube.com/@codingnepal --> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>AI Image Generator | CodingNepal</title> <!-- Font Awesome for icons --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" /> <link rel="stylesheet" href="style.css" /> </head> <body> <div class="container"> <!-- Header --> <header class="header"> <div class="logo-wrapper"> <div class="logo"> <i class="fa-solid fa-wand-magic-sparkles"></i> </div> <h1>AI Image Generator</h1> </div> <button class="theme-toggle"> <i class="fa-solid fa-moon"></i> </button> </header> <div class="main-content"> <form action="#" class="prompt-form"> <!-- Prompt Textarea Container --> <div class="prompt-container"> <textarea class="prompt-input" placeholder="Describe your imagination in detail..." spellcheck="false" autofocus required></textarea> <button type="button" class="prompt-btn" title="Get Random Prompt"> <i class="fa-solid fa-dice"></i> </button> </div> <!-- Prompt Actions / Buttons --> <div class="prompt-actions"> <div class="select-wrapper"> <select class="custom-select" id="model-select" required> <option value="" selected disabled>Select Model</option> <option value="black-forest-labs/FLUX.1-dev">FLUX.1-dev</option> <option value="black-forest-labs/FLUX.1-schnell">FLUX.1-schnell</option> <option value="stabilityai/stable-diffusion-xl-base-1.0">Stable Diffusion XL</option> <option value="runwayml/stable-diffusion-v1-5">Stable Diffusion v1.5</option> <option value="stabilityai/stable-diffusion-3-medium-diffusers">Stable Diffusion 3</option> </select> </div> <div class="select-wrapper"> <select class="custom-select" id="count-select" required> <option value="" selected disabled>Image Count</option> <option value="1">1 Image</option> <option value="2">2 Images</option> <option value="3">3 Images</option> <option value="4">4 Images</option> </select> </div> <div class="select-wrapper"> <select class="custom-select" id="ratio-select" required> <option value="" selected disabled>Aspect Ratio</option> <option value="1/1">Square (1:1)</option> <option value="16/9">Landscape (16:9)</option> <option value="9/16">Portrait (9:16)</option> </select> </div> <button type="submit" class="generate-btn"> <i class="fa-solid fa-wand-sparkles"></i> Generate </button> </div> </form> <!-- Result Gallery Grid --> <div class="gallery-grid"></div> </div> </div> <script src="script.js"></script> </body> </html>
If you’d like to customize or try out different models for AI image generation, you can explore the Hugging Face Text-to-Image Models page. To integrate a new model, simply copy its name and add it to the <option>
tag in your index.html
file.
In the style.css
file, style your AI Image Generator to create a sleek and modern design. Play around with colors, layout, and typography to give it a unique and visually appealing look.
/* Importing Google Fonts - Inter */ @import url('https://fonts.googleapis.com/css2?family=Inter:opsz,[email protected],100..900&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Inter", sans-serif; } :root { --color-primary: #5C56E1; --color-primary-dark: #5b21b6; --color-accent: #8B5CF6; --color-card: #FFFFFF; --color-input: #F1F1FF; --color-text: #09090E; --color-placeholder: #5C5A87; --color-border: #D4D4ED; --color-gradient: linear-gradient(135deg, #5C56E1, #8B5CF6); } body.dark-theme { --color-card: #1E293B; --color-input: #141B2D; --color-text: #F3F4F6; --color-placeholder: #A3B6DC; --color-border: #334155; background: var(--color-card); background-image: radial-gradient(circle at 15% 50%, rgba(99, 102, 241, 0.15) 0%, transparent 35%), radial-gradient(circle at 85% 30%, rgba(139, 92, 246, 0.15) 0%, transparent 35%), radial-gradient(circle at 50% 80%, rgba(99, 102, 241, 0.1) 0%, transparent 40%); } body { display: flex; width: 100%; padding: 15px; align-items: center; justify-content: center; min-height: 100vh; color: var(--color-text); background-image: linear-gradient(#E9E9FF, #C8C7FF); } .container { width: 900px; padding: 32px; border-radius: 23px; position: relative; background: var(--color-card); box-shadow: 0 10px 20px 0 rgba(0, 0, 0, 0.1); transition: all 0.3s ease; overflow: hidden; } .container::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 6px; background-image: var(--color-gradient); } body.dark-theme .container { border: 1px solid var(--color-border); } .header { display: flex; align-items: center; margin-bottom: 32px; justify-content: space-between; } .header .logo-wrapper { display: flex; gap: 18px; align-items: center; } .header .logo-wrapper .logo { height: 55px; width: 56px; display: flex; color: #fff; flex-shrink: 0; font-size: 1.35rem; align-items: center; border-radius: 15px; justify-content: center; background-image: var(--color-gradient); } .header .logo-wrapper h1 { font-size: 1.9rem; font-weight: 700; } .header .theme-toggle { height: 43px; width: 43px; display: flex; font-size: 1.05rem; cursor: pointer; flex-shrink: 0; align-items: center; justify-content: center; border-radius: 50%; color: var(--color-placeholder); background: var(--color-input); border: 1px solid var(--color-border); transition: all 0.3s ease; } .header .theme-toggle:hover { color: var(--color-primary); transform: translateY(-2px); box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); } .main-content { margin: 35px 0 5px 0; } .prompt-container { position: relative; width: 100%; margin-bottom: 20px; } .prompt-container .prompt-input { width: 100%; line-height: 1.6; resize: vertical; font-size: 1.05rem; padding: 16px 20px; min-height: 120px; border-radius: 15px; color: var(--color-text); background: var(--color-input); border: 1px solid var(--color-border); transition: all 0.3s ease; } .prompt-container .prompt-input:focus { border-color: var(--color-accent); box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.15); outline: none; } .prompt-container .prompt-input::placeholder { color: var(--color-placeholder); } .prompt-container .prompt-btn { position: absolute; right: 15px; bottom: 15px; height: 35px; width: 35px; display: flex; font-size: 0.75rem; align-items: center; justify-content: center; background: var(--color-gradient); color: #fff; border: none; border-radius: 50%; cursor: pointer; opacity: 0.8; transition: all 0.3s ease; } .prompt-container .prompt-btn:hover { opacity: 1 !important; transform: translateY(-2px); box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); } .main-content .prompt-actions { display: grid; gap: 15px; grid-template-columns: 1.2fr 1fr 1.1fr 1fr; } .prompt-actions .select-wrapper { position: relative; } .prompt-actions .select-wrapper::after { content: "\f078"; font-family: "Font Awesome 6 Free"; font-weight: 900; position: absolute; right: 20px; top: 50%; padding-left: 7px; background: var(--color-input); transform: translateY(-50%); color: var(--color-placeholder); pointer-events: none; font-size: 0.9rem; transition: all 0.3s ease; } .prompt-actions :where(.custom-select, .generate-btn) { border-radius: 10px; cursor: pointer; font-size: 1rem; padding: 12px 20px; color: var(--color-text); background: var(--color-input); border: 1px solid var(--color-border); transition: all 0.3s ease; } .prompt-actions .select-wrapper .custom-select { width: 100%; outline: none; height: 100%; appearance: none; } .prompt-actions .custom-select:is(:focus, :hover) { border-color: var(--color-accent); box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1); } .prompt-actions .generate-btn { display: flex; gap: 12px; font-weight: 500; border: none; color: #fff; margin-left: auto; align-items: center; justify-content: center; padding: 12px 25px; background-image: var(--color-gradient); } .prompt-actions .generate-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 10px rgba(109, 40, 217, 0.3); } .prompt-actions .generate-btn:disabled { opacity: 0.6; pointer-events: none; } .main-content .gallery-grid { display: grid; gap: 15px; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); } .main-content .gallery-grid:has(.img-card) { margin-top: 30px; } .gallery-grid .img-card { display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; overflow: hidden; border-radius: 16px; opacity: 0; transform: translateY(20px); transition: all 0.5s ease; background: var(--color-input); border: 1px solid var(--color-border); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .gallery-grid .img-card.animate-in { opacity: 1; transform: translateY(0); } .gallery-grid .img-card:not(.loading, .error):hover { transform: translateY(-5px); box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); } .gallery-grid .img-card.loading .spinner { width: 35px; height: 35px; border-radius: 50%; border: 3px solid var(--color-border); border-top-color: var(--color-primary); animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .gallery-grid .img-card .status-container { display: none; gap: 13px; padding: 15px; align-items: center; flex-direction: column; } .gallery-grid .img-card:where(.loading, .error) .status-container { display: flex; } .gallery-grid .img-card.error .spinner, .gallery-grid .img-card.loading i { display: none; } .gallery-grid .img-card .status-container .status-text { font-size: 0.85rem; text-align: center; color: var(--color-placeholder); } .gallery-grid .img-card .status-container i { font-size: 1.7rem; color: #ef4444; } .gallery-grid .img-card .result-img { width: 100%; height: 100%; object-fit: cover; transition: all 0.3s ease; } .gallery-grid .img-card .img-overlay { position: absolute; bottom: 0; left: 0; right: 0; padding: 20px; opacity: 0; display: flex; justify-content: flex-end; transition: all 0.3s ease; background: linear-gradient(transparent, rgba(0, 0, 0, 0.8)); } .gallery-grid .img-card:hover .img-overlay { opacity: 1; } .gallery-grid .img-card:where(.loading, .error) :is(.result-img, .img-overlay) { display: none; } .gallery-grid .img-card .img-download-btn { height: 45px; width: 45px; display: flex; align-items: center; justify-content: center; border: none; color: #fff; cursor: pointer; backdrop-filter: blur(5px); border-radius: 50%; background: rgba(255, 255, 255, 0.25); transition: all 0.3s ease; } .gallery-grid .img-card .img-download-btn:hover { background: rgba(255, 255, 255, 0.4); transform: scale(1.05); } /* Responsive media query code for small screens */ @media (max-width: 768px) { .container { padding: 18px; } .header .logo-wrapper .logo { height: 50px; width: 51px; font-size: 1.25rem; } .header .logo-wrapper h1 { font-size: 1.7rem; } .main-content .prompt-actions { grid-template-columns: 1fr; margin-top: -10px; } .prompt-actions .generate-btn { margin: 10px 0 0; } .gallery-grid .img-card .img-overlay { opacity: 1; } }
In the script.js
file, you’ll add interactivity to your AI Image Generator. The script handles user inputs like the text prompt, selected model, and image settings, then connects to the Hugging Face API to generate the images. It also allows users to switch between light and dark modes.
Be sure to check the comments in the code to understand the purpose of each section and how it all works together.
const promptForm = document.querySelector(".prompt-form"); const themeToggle = document.querySelector(".theme-toggle"); const promptBtn = document.querySelector(".prompt-btn"); const promptInput = document.querySelector(".prompt-input"); const generateBtn = document.querySelector(".generate-btn"); const galleryGrid = document.querySelector(".gallery-grid"); const modelSelect = document.getElementById("model-select"); const countSelect = document.getElementById("count-select"); const ratioSelect = document.getElementById("ratio-select"); const API_KEY = "PASTE-YOUR-API-KEY"; // Hugging Face API Key // Example prompts const examplePrompts = [ "A magic forest with glowing plants and fairy homes among giant mushrooms", "An old steampunk airship floating through golden clouds at sunset", "A future Mars colony with glass domes and gardens against red mountains", "A dragon sleeping on gold coins in a crystal cave", "An underwater kingdom with merpeople and glowing coral buildings", "A floating island with waterfalls pouring into clouds below", "A witch's cottage in fall with magic herbs in the garden", "A robot painting in a sunny studio with art supplies around it", "A magical library with floating glowing books and spiral staircases", "A Japanese shrine during cherry blossom season with lanterns and misty mountains", "A cosmic beach with glowing sand and an aurora in the night sky", "A medieval marketplace with colorful tents and street performers", "A cyberpunk city with neon signs and flying cars at night", "A peaceful bamboo forest with a hidden ancient temple", "A giant turtle carrying a village on its back in the ocean", ]; // Set theme based on saved preference or system default (() => { const savedTheme = localStorage.getItem("theme"); const systemPrefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; const isDarkTheme = savedTheme === "dark" || (!savedTheme && systemPrefersDark); document.body.classList.toggle("dark-theme", isDarkTheme); themeToggle.querySelector("i").className = isDarkTheme ? "fa-solid fa-sun" : "fa-solid fa-moon"; })(); // Switch between light and dark themes const toggleTheme = () => { const isDarkTheme = document.body.classList.toggle("dark-theme"); localStorage.setItem("theme", isDarkTheme ? "dark" : "light"); themeToggle.querySelector("i").className = isDarkTheme ? "fa-solid fa-sun" : "fa-solid fa-moon"; }; // Calculate width/height based on chosen ratio const getImageDimensions = (aspectRatio, baseSize = 512) => { const [width, height] = aspectRatio.split("/").map(Number); const scaleFactor = baseSize / Math.sqrt(width * height); let calculatedWidth = Math.round(width * scaleFactor); let calculatedHeight = Math.round(height * scaleFactor); // Ensure dimensions are multiples of 16 (AI model requirements) calculatedWidth = Math.floor(calculatedWidth / 16) * 16; calculatedHeight = Math.floor(calculatedHeight / 16) * 16; return { width: calculatedWidth, height: calculatedHeight }; }; // Replace loading spinner with the actual image const updateImageCard = (index, imageUrl) => { const imgCard = document.getElementById(`img-card-${index}`); if (!imgCard) return; imgCard.classList.remove("loading"); imgCard.innerHTML = `<img class="result-img" src="${imageUrl}" /> <div class="img-overlay"> <a href="${imageUrl}" class="img-download-btn" title="Download Image" download> <i class="fa-solid fa-download"></i> </a> </div>`; }; // Send requests to Hugging Face API to create images const generateImages = async (selectedModel, imageCount, aspectRatio, promptText) => { const MODEL_URL = `https://api-inference.huggingface.co/models/${selectedModel}`; const { width, height } = getImageDimensions(aspectRatio); generateBtn.setAttribute("disabled", "true"); // Create an array of image generation promises const imagePromises = Array.from({ length: imageCount }, async (_, i) => { try { // Send request to the AI model API const response = await fetch(MODEL_URL, { method: "POST", headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json", "x-use-cache": "false", }, body: JSON.stringify({ inputs: promptText, parameters: { width, height }, }), }); if (!response.ok) throw new Error((await response.json())?.error); // Convert response to an image URL and update the image card const blob = await response.blob(); updateImageCard(i, URL.createObjectURL(blob)); } catch (error) { console.error(error); const imgCard = document.getElementById(`img-card-${i}`); imgCard.classList.replace("loading", "error"); imgCard.querySelector(".status-text").textContent = "Generation failed! Check console for more details."; } }); await Promise.allSettled(imagePromises); generateBtn.removeAttribute("disabled"); }; // Create placeholder cards with loading spinners const createImageCards = (selectedModel, imageCount, aspectRatio, promptText) => { galleryGrid.innerHTML = ""; for (let i = 0; i < imageCount; i++) { galleryGrid.innerHTML += ` <div class="img-card loading" id="img-card-${i}" style="aspect-ratio: ${aspectRatio}"> <div class="status-container"> <div class="spinner"></div> <i class="fa-solid fa-triangle-exclamation"></i> <p class="status-text">Generating...</p> </div> </div>`; } // Stagger animation document.querySelectorAll(".img-card").forEach((card, i) => { setTimeout(() => card.classList.add("animate-in"), 100 * i); }); generateImages(selectedModel, imageCount, aspectRatio, promptText); // Generate Images }; // Handle form submission const handleFormSubmit = (e) => { e.preventDefault(); // Get form values const selectedModel = modelSelect.value; const imageCount = parseInt(countSelect.value) || 1; const aspectRatio = ratioSelect.value || "1/1"; const promptText = promptInput.value.trim(); createImageCards(selectedModel, imageCount, aspectRatio, promptText); }; // Fill prompt input with random example (typing effect) promptBtn.addEventListener("click", () => { const prompt = examplePrompts[Math.floor(Math.random() * examplePrompts.length)]; let i = 0; promptInput.focus(); promptInput.value = ""; // Disable the button during typing animation promptBtn.disabled = true; promptBtn.style.opacity = "0.5"; // Typing effect const typeInterval = setInterval(() => { if (i < prompt.length) { promptInput.value += prompt.charAt(i); i++; } else { clearInterval(typeInterval); promptBtn.disabled = false; promptBtn.style.opacity = "0.8"; } }, 10); // Speed of typing }); themeToggle.addEventListener("click", toggleTheme); promptForm.addEventListener("submit", handleFormSubmit);
Important: Your AI Image Generator won’t be able to generate images until you configure it with the Hugging Face API key. To do this, simply add your API key to the API_KEY variable in the script.js
file. You can get a free API key from Hugging Face Tokens. The key will look something like this: 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.
Once you’ve added your API key, your Image Generator will be all set! Just open the index.html
file in your browser, and you’ll be ready to start generating images.
Conclusion and final words
Congratulations! You’ve successfully built your very own AI Image Generator using HTML, CSS, and JavaScript. This project not only teaches you how to integrate AI into a web tool but also strengthens your skills in API integration, DOM manipulation, and creating a user-friendly design. With features like prompt-based image generation and theme switching, your tool is both functional and visually appealing.
But don’t stop here! You can enhance your generator with features like image editing, model customization, or image sharing. To level up your skills further, check out my previous post on building a Gemini AI chatbot using HTML, CSS, and JavaScript. It covers AI chat, file uploads, and theme switching with the free Gemini API.
If you run into any issues, you can download the source code for the AI Image Generator project by clicking the “Download” button. Be sure to check the README.md
file for setup and usage instructions. If you need help, you’ll find support details there as well.
wow.. working
please create youtube like button..
Html, css, javascript + api(real like system)
But It’s amazing bro. Keep it up.
I paid and I’ve the website but when generating Image it says: “Generation failed! Check console for more details.”!
Sometimes, image generation may fail due to server load or other reasons. However, you can try again shortly or use a different model.