Quick answer
The regex for a CSS hex color is ^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$. It requires a # followed by exactly 3, 4, 6 or 8 hex digits: #fff, #3b82f6, and the alpha forms #fff8 and #3b82f680. Lengths 5 and 7 are rejected because CSS defines no such colors.
- Tested examples
- Token-by-token breakdown
- Code in 5 languages
- Live tester
How to use the hex color regex
- 1Copy the pattern with Copy pattern in the tester, or take a ready-made snippet for your language from the code section below.
- 2Check the sample lines in Test string: every line the hex color regex accepts is highlighted, rejected lines stay plain.
- 3Paste your own values one per line to see which pass, and read Explanation for what each part of the pattern does.
- 4Open the Code tab for JavaScript, Python, Go, C#, PHP or Dart with the pattern translated and escaped.
- 5Validate again on the server: client-side checks give users quick feedback, not security.
How does the hex color regex work?
Read it left to right. Each piece below matches one part of the input:
^#Start of the string and a literal hash.[0-9a-fA-F]{3,4}Short form: 3 digits (#RGB) or 4 with alpha (#RGBA). Each digit is doubled: #fa0 is #ffaa00.|[0-9a-fA-F]{6}Or the full form #RRGGBB.|[0-9a-fA-F]{8}Or the full form with alpha, #RRGGBBAA.$End of the string, which is what rules out 5 and 7 digits.
Which strings does the hex color regex match?
The whole input must match, from the first character to the last. Every row below is checked against the pattern by our automated test suite before each release.
| Input | Matches? | Why |
|---|---|---|
#fff | Yes | Short white. |
#3b82f6 | Yes | Six-digit blue. |
#FFAA00 | Yes | Uppercase is fine. |
#3b82f680 | Yes | Eight digits: 50% alpha. |
#abcd | Yes | Four digits: short form with alpha. |
3b82f6 | No | No hash (see the variant below). |
#ggg | No | g is not a hex digit. |
#12345 | No | Five digits do not exist in CSS. |
#1234567 | No | Nor do seven. |
# | No | A hash alone. |
#3b82f6ff00 | No | Ten digits. |
How do I accept hex colors without the hash?
Make the hash optional with #?, then add it back before using the value, so everything you store has one consistent shape:
const HEX = /^#?(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
const normalize = (s) => (HEX.test(s) ? "#" + s.replace(/^#/, "").toLowerCase() : null);To find colors inside a stylesheet, drop the anchors, add the g flag and end with \b so #12345g does not match its first six characters: #(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{3,4})\b. Put the longest alternative first in that version, because without the $ the engine takes the first alternative that fits.
How do I expand short hex colors?
Each short digit is doubled: #fa0 becomes #ffaa00 and #fa08 becomes #ffaa0088. With a replacement:
"#fa0".replace(/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i, "#$1$1$2$2$3$3"); // "#ffaa00"For anything beyond shape checks, such as turning a hex value into RGB, HSL or OKLCH, or checking text contrast, use the color converter and the contrast checker rather than more regex. The hex syntax is defined in CSS Color Module Level 4.
How do I use the hex color regex in JavaScript, Python, Go, C# and PHP?
The pattern is translated for each engine rather than pasted as is: named groups, anchors, escapes, shorthand classes and flags are adjusted so each snippet behaves as closely to the JavaScript version as its engine allows. Differences that remain (Go's RE2 has no lookarounds or backreferences, for example) are called out under each one. The Code tab in the tester above also exports Dart, and updates as you edit the pattern.
JavaScript and TypeScript
const regex = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
function isValid(value) {
return regex.test(value);
}
console.log(isValid("#fff"));Python
import re
pattern = re.compile(r"^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\Z")
def is_valid(value: str) -> bool:
return pattern.search(value) is not None
print(is_valid("#fff"))- JavaScript's $ only matches at the very end of the string. Python's $ also matches before a trailing newline, so the pattern uses \Z instead.
Go
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$`)
fmt.Println(re.MatchString("#fff"))
}C#
using System;
using System.Text.RegularExpressions;
// The timeout stops a pathological input from hanging the thread (ReDoS).
var regex = new Regex(@"^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\z", RegexOptions.None, TimeSpan.FromSeconds(1));
Console.WriteLine(regex.IsMatch("#fff"));- JavaScript's $ only matches at the very end of the string. .NET's $ also matches before a trailing newline, so the pattern uses \z instead.
PHP
<?php
$pattern = '/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/D';
function isValid(string $value, string $pattern): bool
{
return preg_match($pattern, $value) === 1;
}
var_dump(isValid('#fff', $pattern));- The D modifier makes $ match only at the very end, like JavaScript (PCRE's $ also matches before a trailing newline).
Which related regex patterns are useful?
- Regex for UUIDs (Versions 1–8): 8-4-4-4-12 hex layout with a real version digit (1–8) and the standard variant.
- Regex for MAC Addresses: Six hex pairs with consistent : or - separators, or Cisco's dotted form.
- Regex for Alphanumeric Characters: Letters A–Z and digits only, with a Unicode variant for every script.
- Regex for HTML Tags: Opening, closing and self-closing tags, capturing the tag name.
Browse all 25 patterns in the regex pattern library, or build your own in the regex tester.
Frequently asked questions
Last updated by the Playxoft engineering team.