Posted in

Learn how to create a Color Picker & Palette Generator using HTML, CSS & JS with full code, tooltips, and interactive design examples.

Color Palette Generator

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?

Before diving into the code, let’s understand the value of this project:

  1. Practical Tool: Designers can quickly pick colors and generate palettes for websites or applications.
  2. Learn Front-End Concepts: The project involves DOM manipulation, event handling, CSS styling, and animations, which are fundamental for any web developer.
  3. Copyable & Extendable: Every part of this project is written in vanilla JavaScript, making it easy to read, copy, and modify.
  4. 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 .txt file.
  • 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

  1. DOCTYPE and HTML:
    • <!DOCTYPE html> declares HTML5.
    • <html lang="en"> sets the language.
  2. 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.
  3. Body Section:
    • .container wraps the whole app for layout purposes.
    • .color-picker-section contains:
      • <input type="color"> – color selection.
      • Copy HEX button – copies the selected color.
      • <p> – displays the selected HEX value.
    • .palette-section contains:
      • Gradient type buttons: solid, linear, radial.
      • .palette div – where generated color boxes appear.
      • Generate Palette button – triggers palette generation.
  4. 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

  1. Reset Section:
    Removes default margins/padding and sets box-sizing: border-box to simplify sizing.
  2. Body Styling:
    • Linear gradient background.
    • Flexbox layout for centering the container.
    • Text color and padding for readability.
  3. Container:
    • Glassmorphism effect with rgba background + backdrop-filter: blur(12px).
    • Rounded corners, shadow, padding.
    • Fade-in animation for smooth entrance.
  4. Headings:
    • Centered, with different sizes for main and subheadings.
  5. Color Picker:
    • Centered with vertical spacing.
    • Hover animation for interactivity.
  6. Buttons:
    • Gradient background, rounded corners.
    • Hover & active effects.
    • Focus outline for accessibility.
  7. Palette Section:
    • Flexbox layout for color boxes.
    • Each .color-box scales 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

  1. Selecting Elements: Get references to color picker, buttons, and palette divs.
  2. Toast System: Dynamic notifications for actions (copied, exported).
  3. Color Picker: Live HEX value update and copy function.
  4. Gradient Type Buttons: Switch between solid, linear, radial.
  5. Generate Palette:
    • randomColor() generates random HEX.
    • Loops 5 times to create color boxes.
    • Each box is clickable to copy its value.
  6. Export Palette:
    • Converts palette into a .txt file for download.
  7. 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

  1. 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.
  2. const copyColorBtn = document.getElementById("copyColor");
    • Gets the button element that copies the color to the clipboard.
  3. const colorValue = document.getElementById("colorValue");
    • References the paragraph that displays the currently selected HEX value.
  4. const palette = document.getElementById("palette");
    • Refers to the div that will hold the generated color boxes.
  5. const generateBtn = document.getElementById("generatePalette");
    • Refers to the “Generate Palette” button.
  6. const gradientButtons = document.querySelectorAll(".gradient-options button");
    • Grabs all buttons inside .gradient-options (solid, linear, radial) as a NodeList.
  7. let currentType = "solid";
    • Stores the currently selected palette type. Default is solid.
  8. 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

  1. function showToast(message)
    • A helper function to show temporary notifications to the user.
  2. let toast = document.createElement("div");
    • Creates a new div element dynamically.
  3. toast.textContent = message;
    • Sets the text of the div to the provided message (e.g., “HEX copied!”).
  4. 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)).
  5. document.body.appendChild(toast);
    • Adds the toast div to the page so it becomes visible in the DOM.
  6. setTimeout(() => { ... }, 50);
    • Slight delay to animate the toast in by changing opacity to 1 and moving it up.
  7. 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

  1. 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.
  2. copyColorBtn.addEventListener("click", ...)
    • Uses navigator.clipboard.writeText() to copy the current color.
    • Then shows a toast notification confirming the copy.

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

  1. gradientButtons.forEach(btn => { ... })
    • Loops through each gradient type button.
  2. btn.addEventListener("click", ...)
    • Runs this function when a gradient button is clicked.
  3. currentType = btn.dataset.type;
    • Sets the current type (solid, linear, or radial) based on data-type attribute.
  4. gradientButtons.forEach(b => b.style.opacity = "0.6");
    • Dim all buttons to indicate they’re not selected.
  5. btn.style.opacity = "1";
    • Highlight the clicked button.
  6. 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

  1. generateBtn.addEventListener("click", generatePalette);
    • When the “Generate Palette” button is clicked, this function runs.
  2. 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.
  3. palette.innerHTML = "";
    • Clears any previously generated palette.
  4. currentPalette = [];
    • Resets the palette array for storing new colors.
  5. for (let i = 0; i < 5; i++) { ... }
    • Generates 5 color boxes.
  6. const c1 = randomColor(); const c2 = randomColor();
    • Two random colors for gradients.
  7. let value = "";
    • Stores the color or gradient that will be applied.
  8. if (currentType === "solid")
    • Checks the current type and sets value accordingly.
    • solid – single color.
    • linear – linear gradient.
    • radial – radial gradient.
  9. box.addEventListener("click", ...)
    • Copies the clicked color/gradient to the clipboard.
    • Shows a toast notification.
  10. 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

  1. const exportBtn = document.createElement("button");
    • Dynamically creates a new button for exporting the palette.
  2. generateBtn.after(exportBtn);
    • Places the button after the Generate Palette button in the HTML.
  3. exportBtn.addEventListener("click", ...)
    • When clicked, creates a .txt file with palette info.
  4. let text = ...
    • Builds the file content: first the palette type, then each color.
  5. const blob = new Blob([text], { type: "text/plain" });
    • Converts text into a downloadable file object.
  6. const link = document.createElement("a"); link.href = URL.createObjectURL(blob);
    • Creates a temporary link to download the blob.
  7. link.download = "palette.txt"; link.click();
    • Triggers the download automatically.
  8. 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

BlockPurpose
ElementsGet HTML references for manipulation
ToastDisplay temporary notifications for user actions
Color PickerUpdate HEX live and copy selected color
Gradient ButtonsSwitch palette type and generate new palettes
Palette GenerationDynamically create 5 color boxes based on type
Export PaletteSave the palette as .txt
Initial LoadAuto-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

  1. Top 5 Mistakes Beginners Make While Learning to Code (And How to Avoid Them)
  2. Best Programming Languages to Learn in 2025 (and Why)
  3. Before You Learn Web Development: The Advice No One Gave Me
  4. How to Start Coding in 2025: Beginner’s Roadmap
  5. Why Coding is Important: The Language of the Future
  6. Are Coding and Programming the Same? – The Complete Truth You Need to Know
  7. Will Coding Be Replaced by AI?
  8. C++ Programming: Everything You Need to Know

I’m Shaurya, a developer simplifying tech with tutorials, tools, and projects to help you learn, build, and grow in the world of coding.

Leave a Reply

Your email address will not be published. Required fields are marked *