Developer Toolbox

Regex: Hex color

CSS accepts hex colors with 3, 4, 6 or 8 digits after the #. The 4- and 8-digit forms carry an alpha channel: #1e293b80 is that color at about half opacity. The pattern accepts exactly those four lengths, in either case.

Open in Regex Tester The pattern and every example below are filled in.

Pattern

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

How it works

^#
Start of the string and the #.
(?:[0-9a-fA-F]{3,4}|
Three or four hex digits (#fff, #fff8), or
[0-9a-fA-F]{6}|
six (#1e293b), or
[0-9a-fA-F]{8})
eight, with alpha (#1e293b80).
$
End of the string.

Matches

  • #fff
  • #1e293b
  • #1e293b80
  • #ABCD

Doesn't match

  • fff
  • #ff
  • #12345
  • #ggg

In your language

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

A literal; new RegExp(source, flags) builds the same from a string.

Python
re.compile(r"^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$")

A raw string, so backslashes reach re as written. re.ASCII keeps \d to 0-9, as in JavaScript (Python matches any Unicode digit otherwise). Use re.fullmatch to test a whole string.

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

A normal string literal, so every backslash is doubled. matcher(s).matches() tests the whole string.

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

A raw string in backticks. RE2 runs in linear time but has no lookaround and no backreferences.

PHP
preg_match('/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/D', $input)

PCRE with / delimiters inside a single-quoted string. Without the D modifier, $ also matches before a final newline, so it is added to patterns that end in $.

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

A verbatim string: backslashes stay, a quote is doubled. RegexOptions.ECMAScript keeps \d to 0-9, as in JavaScript. $ also matches before a final newline; to reject one, end the pattern with \z instead.

Common mistakes

  • Five and seven digits are not colors

    #12345 means nothing in CSS. A shorter pattern like #[0-9a-fA-F]{3,8} would let it through, which is why the lengths are listed one by one.

  • CSS has more than hex

    rgb(30 41 59), hsl(...), oklch(...) and names like rebeccapurple or transparent are colors too. To accept anything CSS accepts, ask the browser: CSS.supports("color", value).

  • Normalize before comparing

    #FFF, #fff and #ffffff are the same color. Lower-case and expand the short form before storing or comparing.