나는 바닐라 자바스크립트로 색상 팔레트 생성기를 만들었다

작성자

카테고리:

← 피드로
DEV Community · Praise Oluleye · 2026-08-07 개발(SW)
Cover image for I Built a Colour Palette Generator with Vanilla JavaScript

Praise Oluleye

As part of my journey toward becoming a software engineer, I’ve committed to shipping one project a week using just HTML, CSS, and JavaScript before I move on to frameworks. This week’s project: a Colour Palette Generator.

It’s a simple idea — click a button, get five random colors, click a color to copy its hex code. But small projects like this are great for practicing fundamentals: DOM manipulation, event delegation, and working with browser APIs like Clipboard.

What it does

  • Generates a random 5-color palette on load and on button click
  • Click any swatch (or its copy icon) to copy the hex code straight to your clipboard
  • Shows a quick visual confirmation — the copy icon morphs into a checkmark for 1.5 seconds
  • Fully responsive grid that reflows on smaller screens

The core logic

Generating a random hex color is the easiest part — just pick 6 random characters from the hex alphabet:

function generateRandomColor() {
    const letters = "0123456789ABCDEF";
    let color = "#";

    for (let i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}

Enter fullscreen mode Exit fullscreen mode

Then it’s a matter of generating 5 of these and mapping them onto the color boxes already in the DOM:

function updatePaletteDisplay(colors) {
    const colorBoxes = document.querySelectorAll(".color-box");

    colorBoxes.forEach((box, index) => {
        const color = colors[index];
        const colorDiv = box.querySelector(".color");
        const hexValue = box.querySelector(".hex-value");

        colorDiv.style.backgroundColor = color;
        hexValue.textContent = color;
    });
}

Enter fullscreen mode Exit fullscreen mode

The part I actually learned something from: event delegation

Instead of attaching a click listener to every single copy icon (there are 5, but imagine if the palette size were dynamic), I attached one listener to the parent container and checked what was actually clicked:

paletteContainer.addEventListener("click", function(e) {
    if (e.target.classList.contains("copy-btn")) {
        const hexValue = e.target.previousElementSibling.textContent;

        navigator.clipboard
            .writeText(hexValue)
            .then(() => showCopySuccess(e.target))
            .catch((err) => console.log(err));
    } else if (e.target.classList.contains("color")) {
        const hexValue = e.target.nextElementSibling.querySelector(".hex-value").textContent;
        navigator.clipboard.writeText(hexValue)
            .then(() => showCopySuccess(e.target.nextElementSibling.querySelector(".copy-btn")))
            .catch((err) => console.log(err));
    }
});

Enter fullscreen mode Exit fullscreen mode

This is a pattern I keep coming back to — it’s more performant, and it means new elements added to the DOM later would still “just work” without rebinding anything.

Using the Clipboard API

This was my first time reaching for navigator.clipboard.writeText() outside a tutorial. It’s a Promise-based API, so I handled the copy confirmation in the .then():

function showCopySuccess(element) {
    element.classList.remove("far", "fa-copy");
    element.classList.add("fas", "fa-check");
    element.style.color = "#48bb78";

    setTimeout(() => {
        element.classList.remove("fas", "fa-check");
        element.classList.add("far", "fa-copy");
        element.style.color = "";
    }, 1500);
}

Enter fullscreen mode Exit fullscreen mode

Small detail, but that little swap from a copy icon to a checkmark makes the interaction feel a lot more responsive than a plain alert().

What I’d add next

  • Locking specific colors so they don’t change on regenerate
  • Saving favorite palettes with localStorage
  • A keyboard shortcut (spacebar) to generate a new palette
  • Exporting the palette as CSS variables

Code’s on GitHub: Praise-04-dev

Would love feedback from anyone who’s built something similar — did you handle the clipboard interaction differently?

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다