Choosing the right color palette is one of the most crucial steps in web design and UI development. Colors affect user experience, readability, aesthetics, and even emotional impact. But manually picking colors can be tedious and error-prone. That’s why building a Color Picker & Palette Generator is both fun and practical, especially for beginner and intermediate developers.
In this blog, we’ll go step by step to build a complete tool using HTML, CSS, and JavaScript. By the end, you’ll understand the code fully and be able to extend it for your projects.
Contents Table
- Why Build a Color Picker & Palette Generator?
- Project Features
- Step 1: HTML Structure
- Step 2: CSS Styling
- Step 3: JavaScript Logic
- Detailed JavaScript Explanation – Color Picker & Palette Generator
- Summary of JS Blocks
- Practical Tips for Learners
- Conclusion
Why Build a Color Picker & Palette Generator?
Before diving into the code, let’s understand the value of this project:
- Practical Tool: Designers can quickly pick colors and generate palettes for websites or applications.
- Learn Front-End Concepts: The project involves DOM manipulation, event handling, CSS styling, and animations, which are fundamental for any web developer.
- Copyable & Extendable: Every part of this project is written in vanilla JavaScript, making it easy to read, copy, and modify.
- Portfolio Project: This is a great small project to showcase your skills on GitHub or in a portfolio.
Project Features
Here’s what this tool can do:
- Pick any color using a color picker input.
- Copy the selected color to the clipboard with one click.
- Generate 5 random color palettes at a time.
- Switch between solid, linear gradient, and radial gradient palettes.
- Copy any generated palette color.
- Export the palette as a
.txtfile. - Beautiful glassmorphism UI with hover animations and responsive design.
Step 1: HTML Structure
HTML is the foundation of our application. It defines the structure and provides the elements that JavaScript will manipulate.
Here’s the complete HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Color Picker & Palette Generator</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Color Picker & Palette Generator</h1>
<!-- Color Picker Section -->
<div class="color-picker-section">
<input type="color" id="colorPicker" value="#ffffff">
<button id="copyColor">Copy HEX</button>
<p id="colorValue">#ffffff</p>
</div>
<!-- Palette Generator Section -->
<div class="palette-section">
<h2>Palette Generator</h2>
<!-- Gradient Type Selection Buttons -->
<div class="gradient-options">
<button data-type="solid">Solid</button>
<button data-type="linear">Linear</button>
<button data-type="radial">Radial</button>
</div>
<!-- Display Generated Colors -->
<div class="palette" id="palette"></div>
<!-- Button to Generate Palette -->
<button id="generatePalette">Generate Palette</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
HTML Explanation
- DOCTYPE and HTML:
<!DOCTYPE html>declares HTML5.<html lang="en">sets the language.
- Head Section:
<meta charset="UTF-8">ensures proper character encoding.<meta name="viewport">makes the page responsive on all devices.<title>sets the page title.<link rel="stylesheet">connects our CSS file.
- Body Section:
.containerwraps the whole app for layout purposes..color-picker-sectioncontains:<input type="color">– color selection.Copy HEXbutton – copies the selected color.<p>– displays the selected HEX value.
.palette-sectioncontains:- Gradient type buttons:
solid,linear,radial. .palettediv – where generated color boxes appear.Generate Palettebutton – triggers palette generation.
- Gradient type buttons:
- Script:
<script src="script.js"></script>loads the JavaScript file responsible for all interactivity.
This HTML is clean and semantic, making it easy for beginners to understand.
Step 2: CSS Styling
CSS provides visual appeal, layout, and animations. Let’s go through the complete CSS code:
/* =====================
RESET
===================== */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* =====================
PAGE BACKGROUND
===================== */
body {
font-family: "Segoe UI", Roboto, Arial, sans-serif;
background: linear-gradient(135deg, #667eea, #764ba2);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 40px 15px;
color: #222;
}
/* =====================
MAIN CONTAINER
===================== */
.container {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(12px);
padding: 35px 30px;
border-radius: 18px;
box-shadow: 0 20px 45px rgba(0, 0, 0, 0.25);
max-width: 520px;
width: 100%;
animation: fadeIn 0.6s ease;
}
/* Entrance animation */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* HEADINGS */
h1 {
text-align: center;
margin-bottom: 25px;
font-size: 1.8rem;
}
h2 {
text-align: center;
margin-bottom: 15px;
font-size: 1.2rem;
font-weight: 500;
color: #555;
}
/* COLOR PICKER */
.color-picker-section {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
margin-bottom: 35px;
}
#colorPicker {
width: 130px;
height: 55px;
border-radius: 10px;
border: 2px solid #ddd;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
#colorPicker:hover {
transform: scale(1.05);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
#colorValue {
font-weight: bold;
letter-spacing: 0.5px;
}
/* BUTTONS */
button {
padding: 10px 22px;
border: none;
border-radius: 12px;
background: linear-gradient(135deg, #6366f1, #8b5cf6);
color: #fff;
font-size: 0.95rem;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
}
button:active {
transform: translateY(0);
}
button:focus {
outline: 2px solid #c7d2fe;
outline-offset: 2px;
}
/* GRADIENT OPTIONS */
.gradient-options {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 18px;
}
.gradient-options button {
padding: 7px 18px;
font-size: 0.85rem;
border-radius: 20px;
opacity: 0.7;
}
.gradient-options button:hover {
opacity: 1;
}
/* PALETTE */
.palette-section {
text-align: center;
}
.palette {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 14px;
margin: 20px 0;
}
.color-box {
width: 70px;
height: 70px;
border-radius: 14px;
cursor: pointer;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.color-box:hover {
transform: scale(1.15);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.4);
}
/* RESPONSIVE */
@media (max-width: 480px) {
.container {
padding: 25px 20px;
}
.color-box {
width: 55px;
height: 55px;
}
}
CSS Explanation
- Reset Section:
Removes default margins/padding and setsbox-sizing: border-boxto simplify sizing. - Body Styling:
- Linear gradient background.
- Flexbox layout for centering the container.
- Text color and padding for readability.
- Container:
- Glassmorphism effect with
rgbabackground +backdrop-filter: blur(12px). - Rounded corners, shadow, padding.
- Fade-in animation for smooth entrance.
- Glassmorphism effect with
- Headings:
- Centered, with different sizes for main and subheadings.
- Color Picker:
- Centered with vertical spacing.
- Hover animation for interactivity.
- Buttons:
- Gradient background, rounded corners.
- Hover & active effects.
- Focus outline for accessibility.
- Palette Section:
- Flexbox layout for color boxes.
- Each
.color-boxscales and casts shadow on hover. - Responsive: adjusts box sizes for smaller screens.
Step 3: JavaScript Logic
Finally, the JS file makes the app interactive:
/* ELEMENTS */
const colorPicker = document.getElementById("colorPicker");
const copyColorBtn = document.getElementById("copyColor");
const colorValue = document.getElementById("colorValue");
const palette = document.getElementById("palette");
const generateBtn = document.getElementById("generatePalette");
const gradientButtons = document.querySelectorAll(".gradient-options button");
let currentType = "solid";
let currentPalette = [];
/* TOAST NOTIFICATIONS */
function showToast(message) {
let toast = document.createElement("div");
toast.textContent = message;
Object.assign(toast.style, {
position: "fixed",
bottom: "30px",
right: "30px",
background: "linear-gradient(135deg, #6366f1, #8b5cf6)",
color: "#fff",
padding: "12px 18px",
borderRadius: "10px",
fontSize: "0.9rem",
boxShadow: "0 10px 25px rgba(0,0,0,0.3)",
zIndex: "9999",
opacity: "0",
transform: "translateY(20px)",
transition: "all 0.3s ease"
});
document.body.appendChild(toast);
setTimeout(() => {
toast.style.opacity = "1";
toast.style.transform = "translateY(0)";
}, 50);
setTimeout(() => {
toast.style.opacity = "0";
toast.style.transform = "translateY(20px)";
setTimeout(() => toast.remove(), 300);
}, 2000);
}
/* COLOR PICKER */
colorPicker.addEventListener("input", () => {
colorValue.textContent = colorPicker.value;
});
copyColorBtn.addEventListener("click", () => {
navigator.clipboard.writeText(colorPicker.value);
showToast("HEX copied!");
});
/* GRADIENT BUTTONS */
gradientButtons.forEach(btn => {
btn.addEventListener("click", () => {
currentType = btn.dataset.type;
gradientButtons.forEach(b => b.style.opacity = "0.6");
btn.style.opacity = "1";
generatePalette();
});
});
/* GENERATE PALETTE */
generateBtn.addEventListener("click", generatePalette);
function randomColor() {
return "#" + Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0");
}
function generatePalette() {
palette.innerHTML = "";
currentPalette = [];
for (let i = 0; i < 5; i++) {
const c1 = randomColor();
const c2 = randomColor();
const box = document.createElement("div");
box.className = "color-box";
let value = "";
if (currentType === "solid") value = c1;
if (currentType === "linear") value = `linear-gradient(135deg, ${c1}, ${c2})`;
if (currentType === "radial") value = `radial-gradient(circle, ${c1}, ${c2})`;
box.style.background = value;
currentPalette.push(value);
box.addEventListener("click", () => {
navigator.clipboard.writeText(value);
showToast("Copied to clipboard!");
});
palette.appendChild(box);
}
}
/* EXPORT PALETTE */
const exportBtn = document.createElement("button");
exportBtn.textContent = "Export Palette";
exportBtn.style.marginTop = "10px";
generateBtn.after(exportBtn);
exportBtn.addEventListener("click", () => {
let text = `Palette Type: ${currentType.toUpperCase()}\n\n`;
currentPalette.forEach((color, i) => {
text += `${i + 1}. ${color}\n`;
});
const blob = new Blob([text], { type: "text/plain" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "palette.txt";
link.click();
showToast("Palette exported as TXT!");
});
/* INITIAL LOAD */
generatePalette();
JavaScript Explanation
- Selecting Elements: Get references to color picker, buttons, and palette divs.
- Toast System: Dynamic notifications for actions (copied, exported).
- Color Picker: Live HEX value update and copy function.
- Gradient Type Buttons: Switch between solid, linear, radial.
- Generate Palette:
randomColor()generates random HEX.- Loops 5 times to create color boxes.
- Each box is clickable to copy its value.
- Export Palette:
- Converts palette into a
.txtfile for download.
- Converts palette into a
- Initial Load: Generates a palette when the page loads.
Detailed JavaScript Explanation – Color Picker & Palette Generator
Here’s the full JavaScript file again, but now we will go through it section by section.
/* =============================
ELEMENTS
============================= */
const colorPicker = document.getElementById("colorPicker");
const copyColorBtn = document.getElementById("copyColor");
const colorValue = document.getElementById("colorValue");
const palette = document.getElementById("palette");
const generateBtn = document.getElementById("generatePalette");
const gradientButtons = document.querySelectorAll(".gradient-options button");
let currentType = "solid";
let currentPalette = [];
Explanation
const colorPicker = document.getElementById("colorPicker");- Grabs the color input element from the HTML.
- Used to read the current color value whenever the user picks a color.
const copyColorBtn = document.getElementById("copyColor");- Gets the button element that copies the color to the clipboard.
const colorValue = document.getElementById("colorValue");- References the paragraph that displays the currently selected HEX value.
const palette = document.getElementById("palette");- Refers to the div that will hold the generated color boxes.
const generateBtn = document.getElementById("generatePalette");- Refers to the “Generate Palette” button.
const gradientButtons = document.querySelectorAll(".gradient-options button");- Grabs all buttons inside
.gradient-options(solid, linear, radial) as a NodeList.
- Grabs all buttons inside
let currentType = "solid";- Stores the currently selected palette type. Default is
solid.
- Stores the currently selected palette type. Default is
let currentPalette = [];- An array that holds all the colors/gradients generated for the current palette.
- Useful for copying or exporting the palette.
/* =============================
TOAST NOTIFICATIONS
============================= */
function showToast(message) {
let toast = document.createElement("div");
toast.textContent = message;
Object.assign(toast.style, {
position: "fixed",
bottom: "30px",
right: "30px",
background: "linear-gradient(135deg, #6366f1, #8b5cf6)",
color: "#fff",
padding: "12px 18px",
borderRadius: "10px",
fontSize: "0.9rem",
boxShadow: "0 10px 25px rgba(0,0,0,0.3)",
zIndex: "9999",
opacity: "0",
transform: "translateY(20px)",
transition: "all 0.3s ease"
});
document.body.appendChild(toast);
setTimeout(() => {
toast.style.opacity = "1";
toast.style.transform = "translateY(0)";
}, 50);
setTimeout(() => {
toast.style.opacity = "0";
toast.style.transform = "translateY(20px)";
setTimeout(() => toast.remove(), 300);
}, 2000);
}
Explanation
function showToast(message)- A helper function to show temporary notifications to the user.
let toast = document.createElement("div");- Creates a new div element dynamically.
toast.textContent = message;- Sets the text of the div to the provided message (e.g., “HEX copied!”).
Object.assign(toast.style, { ... });- Styles the toast dynamically using JavaScript object.
- Fixed position at the bottom-right.
- Background gradient, rounded corners, shadow, small size.
- Initially invisible (
opacity: 0) and slightly below (translateY(20px)).
document.body.appendChild(toast);- Adds the toast div to the page so it becomes visible in the DOM.
setTimeout(() => { ... }, 50);- Slight delay to animate the toast in by changing opacity to 1 and moving it up.
setTimeout(() => { ... }, 2000);- After 2 seconds, hides the toast again by fading it out and moving down.
- Then removes the toast from the DOM entirely.
This creates a smooth popup notification system for actions like copying a color.
/* =============================
COLOR PICKER FUNCTIONALITY
============================= */
colorPicker.addEventListener("input", () => {
colorValue.textContent = colorPicker.value;
});
copyColorBtn.addEventListener("click", () => {
navigator.clipboard.writeText(colorPicker.value);
showToast("HEX copied!");
});
Explanation
colorPicker.addEventListener("input", ...)- Listens for any change in the color picker.
- Updates the
<p id="colorValue">with the current HEX value. - This happens live as the user moves the color slider.
copyColorBtn.addEventListener("click", ...)- Uses
navigator.clipboard.writeText()to copy the current color. - Then shows a toast notification confirming the copy.
- Uses
Users can select a color and instantly see its HEX value and copy it with one click.
/* =============================
GRADIENT TYPE SELECTION
============================= */
gradientButtons.forEach(btn => {
btn.addEventListener("click", () => {
currentType = btn.dataset.type; // solid / linear / radial
gradientButtons.forEach(b => b.style.opacity = "0.6"); // Dim others
btn.style.opacity = "1"; // Highlight selected
generatePalette(); // Auto-generate new palette
});
});
Explanation
gradientButtons.forEach(btn => { ... })- Loops through each gradient type button.
btn.addEventListener("click", ...)- Runs this function when a gradient button is clicked.
currentType = btn.dataset.type;- Sets the current type (
solid,linear, orradial) based ondata-typeattribute.
- Sets the current type (
gradientButtons.forEach(b => b.style.opacity = "0.6");- Dim all buttons to indicate they’re not selected.
btn.style.opacity = "1";- Highlight the clicked button.
generatePalette();- Automatically generates a new palette with the selected gradient type.
This allows users to switch between solid colors, linear gradients, and radial gradients easily.
/* =============================
PALETTE GENERATION LOGIC
============================= */
generateBtn.addEventListener("click", generatePalette);
function randomColor() {
return "#" + Math.floor(Math.random() * 16777215)
.toString(16)
.padStart(6, "0");
}
function generatePalette() {
palette.innerHTML = "";
currentPalette = [];
for (let i = 0; i < 5; i++) {
const c1 = randomColor();
const c2 = randomColor();
const box = document.createElement("div");
box.className = "color-box";
let value = "";
if (currentType === "solid") {
value = c1;
box.style.background = value;
}
if (currentType === "linear") {
value = `linear-gradient(135deg, ${c1}, ${c2})`;
box.style.background = value;
}
if (currentType === "radial") {
value = `radial-gradient(circle, ${c1}, ${c2})`;
box.style.background = value;
}
currentPalette.push(value);
box.addEventListener("click", () => {
navigator.clipboard.writeText(value);
showToast("Copied to clipboard!");
});
palette.appendChild(box);
}
}
Explanation
generateBtn.addEventListener("click", generatePalette);- When the “Generate Palette” button is clicked, this function runs.
function randomColor() { ... }- Generates a random HEX color.
Math.floor(Math.random() * 16777215)generates a random number in the range of all possible colors..toString(16)converts the number to hexadecimal..padStart(6, "0")ensures it always has 6 digits.
palette.innerHTML = "";- Clears any previously generated palette.
currentPalette = [];- Resets the palette array for storing new colors.
for (let i = 0; i < 5; i++) { ... }- Generates 5 color boxes.
const c1 = randomColor(); const c2 = randomColor();- Two random colors for gradients.
let value = "";- Stores the color or gradient that will be applied.
if (currentType === "solid")…- Checks the current type and sets
valueaccordingly. solid– single color.linear– linear gradient.radial– radial gradient.
- Checks the current type and sets
box.addEventListener("click", ...)- Copies the clicked color/gradient to the clipboard.
- Shows a toast notification.
palette.appendChild(box);- Adds the color box to the HTML page.
This function is the core of the app, dynamically generating color boxes based on type and enabling click-to-copy functionality.
/* =============================
EXPORT PALETTE
============================= */
const exportBtn = document.createElement("button");
exportBtn.textContent = "Export Palette";
exportBtn.style.marginTop = "10px";
generateBtn.after(exportBtn);
exportBtn.addEventListener("click", () => {
let text = `Palette Type: ${currentType.toUpperCase()}\n\n`;
currentPalette.forEach((color, i) => {
text += `${i + 1}. ${color}\n`;
});
const blob = new Blob([text], { type: "text/plain" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "palette.txt";
link.click();
showToast("Palette exported as TXT!");
});
Explanation
const exportBtn = document.createElement("button");- Dynamically creates a new button for exporting the palette.
generateBtn.after(exportBtn);- Places the button after the Generate Palette button in the HTML.
exportBtn.addEventListener("click", ...)- When clicked, creates a
.txtfile with palette info.
- When clicked, creates a
let text = ...- Builds the file content: first the palette type, then each color.
const blob = new Blob([text], { type: "text/plain" });- Converts text into a downloadable file object.
const link = document.createElement("a"); link.href = URL.createObjectURL(blob);- Creates a temporary link to download the blob.
link.download = "palette.txt"; link.click();- Triggers the download automatically.
showToast("Palette exported as TXT!");- Shows a confirmation message.
This allows users to save their generated palettes locally for later use.
/* =============================
INITIAL LOAD
============================= */
generatePalette();
Explanation
- Calls
generatePalette()automatically when the page loads. - Ensures the user sees a palette immediately, even before clicking anything.
Summary of JS Blocks
| Block | Purpose |
|---|---|
| Elements | Get HTML references for manipulation |
| Toast | Display temporary notifications for user actions |
| Color Picker | Update HEX live and copy selected color |
| Gradient Buttons | Switch palette type and generate new palettes |
| Palette Generation | Dynamically create 5 color boxes based on type |
| Export Palette | Save the palette as .txt |
| Initial Load | Auto-generate palette when page loads |
By understanding each block, you can now customize the app, add more colors, or even integrate RGB/HSL formats.
If you want, I can also make a flow diagram explaining how the JavaScript interacts with HTML and CSS, so beginners can visualize every click, event, and update. This would make understanding much easier.
Do you want me to make that diagram?
Practical Tips for Learners
- Experiment with number of colors in the palette.
- Try adding RGB and HSL support.
- Implement local storage to save favorite palettes.
- Add copy all colors at once feature.
- Experiment with animations on palette boxes.
Conclusion
By following this tutorial, you’ve learned how to:
- Build a complete front-end project from scratch.
- Use HTML for structure, CSS for style, and JavaScript for interactivity.
- Implement clipboard functionality, dynamic DOM elements, and export features.
- Use modern UI techniques like glassmorphism, hover animations, and gradients.
This project is perfect for beginners and intermediate developers looking to practice JavaScript DOM manipulation, styling, and interactivity.
Try modifying this project by adding more features. Maybe a dark mode, palette saving, or integration with APIs. The possibilities are endless.
Checkout My YouTube Channel
Read my other Blogs
- Top 5 Mistakes Beginners Make While Learning to Code (And How to Avoid Them)
- Best Programming Languages to Learn in 2025 (and Why)
- Before You Learn Web Development: The Advice No One Gave Me
- How to Start Coding in 2025: Beginner’s Roadmap
- Why Coding is Important: The Language of the Future
- Are Coding and Programming the Same? – The Complete Truth You Need to Know
- Will Coding Be Replaced by AI?
- C++ Programming: Everything You Need to Know
