Toolmingo
Guides6 min read

How to Generate a Random Hex Color (JS, Python, Go, PHP)

Generate random hex color codes in JavaScript, Python, Go, and PHP. Covers pure random, readable random (via HSL), random from a palette, and crypto-safe random.

How to Generate a Random Hex Color

A random hex color is a six-character string like #a3f4c2 that represents a CSS color. You need one when you're seeding placeholder UI, assigning unique colors to dataset entries, building a color-picker demo, or stress-testing a design with unexpected colors.

The naive approach — pick three random bytes and format them as hex — works but produces muddy, unreadable colors roughly 80% of the time. This guide shows the naive approach first, then the smarter HSL-based method that gives you random but usable colors, plus how to pick random colors from a curated palette.


The naive approach: random bytes

Every hex color is three byte values (0–255) packed into #RRGGBB. The simplest random color picks three independent bytes.

JavaScript (browser + Node)

// Math.random — fine for visual placeholders, not cryptographically safe
function randomHex() {
  return '#' + Math.floor(Math.random() * 0xffffff)
    .toString(16)
    .padStart(6, '0');
}

console.log(randomHex()); // e.g. "#4d9c2f"

The padStart(6, '0') is essential: Math.random() can produce values like 0x00a1c4, whose toString(16) is only five characters — without padding you'd get #a1c4 which is a valid three-character shorthand but not what you meant.

Python

import random
import secrets  # use this instead if you need unpredictability

def random_hex():
    return '#{:06x}'.format(random.randint(0, 0xFFFFFF))

def random_hex_secure():
    return '#{:06x}'.format(secrets.randbelow(0x1000000))

print(random_hex())        # e.g. "#7e3ab1"
print(random_hex_secure()) # cryptographically random

Go

package main

import (
    "crypto/rand"
    "fmt"
    "math/big"
)

func randomHex() string {
    n, _ := rand.Int(rand.Reader, big.NewInt(0x1000000))
    return fmt.Sprintf("#%06x", n)
}

func main() {
    fmt.Println(randomHex()) // e.g. "#3f8c2a"
}

Go's crypto/rand is the idiomatic choice — there's no reason to use math/rand for something this simple.

PHP

function randomHex(): string {
    return '#' . str_pad(dechex(random_int(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT);
}

echo randomHex(); // e.g. "#c2794d"

Use random_int, not rand. PHP's rand is seeded with a predictable value on some platforms.


The smarter approach: random HSL

Pure random RGB gives you colors across the full gamut, which includes very dark, very light, very saturated, and very grey colors. If you want colors that are visually distinct and reasonably legible on a white background, generate in HSL and convert to hex.

HSL stands for Hue (0–360°, the color wheel), Saturation (0–100%, how vivid), Lightness (0–100%, how bright). By fixing saturation around 60–70% and lightness around 50–60%, every random hue produces a clear, medium-tone color.

JavaScript

function hslToHex(h, s, l) {
  s /= 100;
  l /= 100;
  const k = n => (n + h / 30) % 12;
  const a = s * Math.min(l, 1 - l);
  const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
  const toHex = x => Math.round(x * 255).toString(16).padStart(2, '0');
  return `#${toHex(f(0))}${toHex(f(8))}${toHex(f(4))}`;
}

function randomReadableHex() {
  const h = Math.floor(Math.random() * 360);  // full hue range
  const s = 55 + Math.random() * 20;          // 55–75 % saturation
  const l = 45 + Math.random() * 15;          // 45–60 % lightness
  return hslToHex(h, s, l);
}

console.log(randomReadableHex()); // always a clear, medium-tone color

Python

import colorsys
import random

def random_readable_hex() -> str:
    h = random.random()                  # 0–1 (full hue wheel)
    s = random.uniform(0.55, 0.75)       # moderate saturation
    l = random.uniform(0.45, 0.60)       # medium lightness
    r, g, b = colorsys.hls_to_rgb(h, l, s)  # Python uses HLS order!
    return '#{:02x}{:02x}{:02x}'.format(
        round(r * 255), round(g * 255), round(b * 255)
    )

print(random_readable_hex())

Note the Python colorsys.hls_to_rgb argument order: H, L, S (lightness before saturation) — the reverse of the HSL convention you know from CSS.


Random color from a palette

When you want random but on-brand, define a palette of approved colors and pick from it randomly. This is the right approach for UI avatar backgrounds, chart series colors, and tag labels.

JavaScript

const PALETTE = [
  '#ef4444', '#f97316', '#eab308', '#22c55e',
  '#06b6d4', '#3b82f6', '#8b5cf6', '#ec4899',
];

function randomFromPalette() {
  return PALETTE[Math.floor(Math.random() * PALETTE.length)];
}

Python

import random

PALETTE = [
    '#ef4444', '#f97316', '#eab308', '#22c55e',
    '#06b6d4', '#3b82f6', '#8b5cf6', '#ec4899',
]

def random_from_palette() -> str:
    return random.choice(PALETTE)

Go

import (
    "crypto/rand"
    "math/big"
)

var palette = []string{
    "#ef4444", "#f97316", "#eab308", "#22c55e",
    "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899",
}

func randomFromPalette() string {
    n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(palette))))
    return palette[n.Int64()]
}

PHP

$palette = [
    '#ef4444', '#f97316', '#eab308', '#22c55e',
    '#06b6d4', '#3b82f6', '#8b5cf6', '#ec4899',
];

function randomFromPalette(array $palette): string {
    return $palette[array_rand($palette)];
}

Unique random colors for multiple items

If you're assigning a color to each item in a list (user avatars, chart lines, category labels), you need unique colors — no repeats. Shuffle the palette and take one per item.

// JavaScript: unique colors from a palette, no repeats
function shuffled(arr) {
  const a = [...arr];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

const colors = shuffled(PALETTE).slice(0, items.length);

If you have more items than palette colors, fall back to generated HSL colors with evenly spaced hues:

function evenlySpacedColors(count) {
  return Array.from({ length: count }, (_, i) => {
    const h = Math.round((i / count) * 360);
    return hslToHex(h, 65, 52);
  });
}

Evenly-spaced hues guarantee maximum perceptual difference between colors — the best choice for distinguishable chart series.


Quick reference

Goal Method Example output
Any random color Random 24-bit integer → hex #4d3ab1 (may be dark/muted)
Legible random color Random HSL, fixed S+L range #6ab84e (always clear)
Brand-consistent color random.choice(palette) #3b82f6
Unique colors for N items Shuffle palette, slice No repeats
Max-distinct colors for N items Evenly-spaced hue, fixed S+L Maximum separation

6 common mistakes

1. Forgetting padStart

Math.floor(Math.random() * 0xffffff).toString(16) can produce a 5-character string for small values. Always .padStart(6, '0') or format with %06x.

2. Using Math.random where security matters

For generating unique IDs, tokens, or anything an attacker could predict, Math.random is not cryptographically safe. Use crypto.getRandomValues (browser), crypto.randomBytes (Node), secrets.randbelow (Python), or crypto/rand (Go).

3. Ignoring readability

Pure random RGB produces gray and near-black colors constantly. If human readability matters, use the HSL approach with constrained saturation and lightness.

4. Generating colors inside a tight render loop

If you're generating a color every frame (animation, live preview), create the color once and store it — don't call the RNG on every render.

5. Assuming #fff and #ffffff are interchangeable in code

Three-character hex shorthand works in CSS but not everywhere. JSON config parsers, Python Pillow, and some SVG renderers expect the full six-character form. Always emit #rrggbb.

6. Storing colors as floats

After converting through HSL or generating as floats, round each channel to an integer before formatting. Math.round(r * 255), not Math.floor — floor causes systematic darkening at the top of each channel.


Frequently asked questions

What does "random hex color" mean exactly?

A hex color is a CSS color code in the format #RRGGBB, where each pair is a two-digit hexadecimal number (00–FF) representing the red, green, and blue channel intensity. A random hex color is one where those values are chosen by a random number generator rather than a human.

How many possible hex colors are there?

#000000 to #FFFFFF gives 16,777,216 (2²⁴) possible colors — one for every combination of 256 × 256 × 256 red/green/blue values.

How do I generate a random dark color for a dark-mode background?

Use the HSL approach and constrain lightness to 10–30%:

const h = Math.floor(Math.random() * 360);
const color = hslToHex(h, 30, 20); // dark, slightly tinted

How do I generate a random light color for a pastel look?

Constrain saturation to 40–60% and lightness to 75–90%:

const h = Math.floor(Math.random() * 360);
const color = hslToHex(h, 50, 82); // pastel

What's the difference between Math.random and crypto.getRandomValues for colors?

Math.random is a pseudo-random number generator (PRNG) — fast, but theoretically predictable if someone knows the seed. crypto.getRandomValues is a cryptographically secure PRNG (CSPRNG) sourced from OS entropy. For visual placeholders either is fine; for anything security-related (tokens, IDs) use the crypto version.

Can I convert the random hex to RGB or HSL for further processing?

Yes — use the Color Converter to convert between hex, RGB, HSL, and HSV instantly. If you need to do it in code, see the hex-to-RGB guide for formulas in all four languages.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools