Skip to content
d.devtul.fun
中文
Regex · Color

Hex Color Regex

A regex that matches every legal hex color, and the stronger claim that you should usually not use one at all.

The pattern

^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$

Matches the three, four, six, and eight digit hex color forms. Rejects anything else, including a missing #.

Test this pattern

Edit the text below — matching happens locally, nothing is uploaded.

Variants

Case-insensitive with the i flag
^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$

Drop the A-F range and pass the case-insensitive flag instead. Same matches, slightly shorter pattern.

Optional #
^#?(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$

Accepts 1a2b3c without the hash. Handy for input fields, but then you must decide what an empty or bare value means.

What this regex matches

The pattern that covers every CSS hex color form:

^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$

Read it left to right:

  • ^# requires the hash. Without it you are matching something that is not a CSS color.
  • The non-capturing group offers three alternatives, tried in order:
    • [0-9a-fA-F]{3,4} covers the three-digit #RGB and four-digit #RGBA shorthand.
    • [0-9a-fA-F]{6} is the classic six-digit #RRGGBB.
    • [0-9a-fA-F]{8} is the eight-digit #RRGGBBAA with alpha.
  • $ anchors the end so trailing junk is rejected.

Why 3, 4, 6, and 8 digits are all legal

CSS defines a shorthand rule: in the 3- and 4-digit forms, each hexadecimal digit is duplicated to produce the full value. So:

FormExampleExpands to
#RGB#f0a#ff00aa
#RGBA#f0a8#ff00aa88
#RRGGBB#ff00aaitself
#RRGGBBAA#ff00aa88itself

That is why the regex must accept both 3 and 4 (not just 3) and both 6 and 8 (not just 6). A pattern that hardcodes {6} silently breaks #fff, which is one of the most common colors on the web.

The case-insensitive option

Hex digits are case-insensitive: #FFF equals #fff. You can write the class as [0-9a-fA-F], or write [0-9a-f] and apply the i flag at compile time. Both match the same strings. Pick the one your language makes cleaner; just do not forget one of them, or #ABCDEF will be rejected.

Whether to allow a missing # is a product decision. In a strict CSS context the hash is mandatory. In a user input field you may accept 1a2b3c and prepend the hash yourself. The regex above requires the hash; the alternate shows the optional version.

Regex cannot tell you if the color will render

This is the core point, and it is worth stating plainly: a regex can only tell you that a string looks like a hex color. It cannot tell you the color is valid CSS, will be applied, or means anything in context.

In a browser you already have a far better validator built in. Use the CSS engine:

function isColor(value) {
  return CSS.supports('color', value);
}

CSS.supports parses the value the same way the browser does, so it accepts #fff, rebeccapurple, rgb(0 0 0 / 50%), and rejects nonsense with the real parser. It also future-proofs you: when a new color syntax ships, the regex breaks and CSS.supports does not.

If you are not in a browser, parse the value yourself or lean on a small, well-tested color library instead of a hand-rolled regex. The regex is fine for "does this string resemble a color in a log file", not for "is this a real color".

Common mistakes

WrongProblemRight
^#[0-9a-f]{6}$Rejects #fff, #ffff, #ffffffff.Include 3,4,6,8 forms.
^[0-9a-f]{6}$Forgets the mandatory #.Require # or decide deliberately.
^#[0-9a-fA-F]{8}$Misses the common 3- and 6-digit forms.All four lengths.
Mixing up #ffff and #ffffffFour digits is RGBA, not a broken six-digit.Treat 4 as RGBA, 8 as RRGGBBAA.

#fff versus #ffff

A frequent source of confusion: #fff is three digits (shorthand RGB). #ffff is four digits, which means #ffff is shorthand RGBA with full alpha, not a malformed six-digit color. Likewise #ffffff is six-digit RGB and #ffffffff is eight-digit RGBA. The digit count alone tells you which channel layout you have, and the regex's alternation reflects exactly that.

Extracting every color from text

Sometimes you do not want to validate one value but to pull all hex colors out of a block of text (a stylesheet dump, a log, user paste). Drop the anchors and use the global flag:

/#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})/g

The  boundary stops #1234567 from matching the first six digits as if they were a color. Remember this is extraction, not validation of intent: a hex string that happens to look like a color is not automatically a color the page uses.

When a regex is the right tool

To be fair, the regex earns its place in narrow cases:

  • Sanity-checking a single value in a non-browser language where no CSS parser exists.
  • Quickly scanning logs or pasted text for color-like tokens.
  • A fast reject at a form's edge before deeper parsing.

But the moment the question is "will this color actually be used", reach for the platform parser. The regex answers "does it look right"; the parser answers "is it right".

Frequently asked

Is a regex enough to validate a CSS color?

No. It only checks the string looks like a color. Use CSS.supports() in the browser to validate for real.

Why does #fff work but my regex rejects it?

You hard-coded six digits. #fff is the three-digit shorthand where each digit is duplicated.

What is the difference between #ffff and #ffffff?

Four digits is shorthand RGBA (with alpha). Six digits is RGB. They are different channel layouts.

Should I allow a hex color without the #?

Only in user input, and prepend the hash yourself. In strict CSS the # is mandatory.

Related regex guides

Open the full Regex Tester