180

For example:

AA33FF = valid hex color

Z34FF9 = invalid hex color (has Z in it)

AA33FF11 = invalid hex color (has extra characters)

2

11 Answers 11

426

Without transparent support:

/^#[0-9A-F]{6}$/i.test('#AABBCC')

With transparent support :

/^#[0-9A-F]{6}[0-9a-f]{0,2}$/i.test('#AABBCC80')

To elaborate:

^ -> match beginning
# -> a hash
[0-9A-F] -> any integer from 0 to 9 and any letter from A to F
{6} -> the previous group appears exactly 6 times
[0-9a-f]{0,2} -> adding support for transparent ( 00..FF)
$ -> match end
i -> ignore case

If you need support for 3-character HEX codes (no transparent supported) , use the following:

/^#([0-9A-F]{3}){1,2}$/i.test('#ABC')

The only difference here is that

 [0-9A-F]{6}

is replaced with

([0-9A-F]{3}){1,2}

This means that instead of matching exactly 6 characters, it will match exactly 3 characters, but only 1 or 2 times. Allowing ABC and AABBCC, but not ABCD

Combined solution :

var reg=/^#([0-9a-f]{3}){1,2}$/i;
console.log(reg.test('#ABC')); //true
console.log(reg.test('#AABBCC')); //true
14
  • 21
    By definition this is correct, but codes with a length of 3 are valid for browser interpretation, too. color: #f00; will be interpreted as red (#ff0000) aswell.
    – Smamatti
    Commented Nov 6, 2011 at 14:13
  • 14
    or another form: /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test("#f00")
    – J. Holmes
    Commented Nov 6, 2011 at 15:22
  • 10
    I would also add /^#([0-9a-f]{3}){1,2}$/i to the mix.
    – MasterAM
    Commented Mar 1, 2016 at 12:57
  • 4
    var isOk = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i.test('#aabbcc'); @RomanBoiko this is right! Thanks! Commented Sep 5, 2016 at 22:56
  • 2
    To include #AARRGGBB format (in addition to #RGB and #RRGGBB already covered): /^#(([A-F0-9]{2}){3,4}|[A-F0-9]{3})$/i (and non-capturing version for improved efficiency: ^#(?:(?:[A-F0-9]{2}){3,4}|[A-F0-9]{3})$). regexr.com/3p38r Commented May 7, 2018 at 21:08
43

// regular function
function isHexColor (hex) {
  return typeof hex === 'string'
      && hex.length === 6
      && !isNaN(Number('0x' + hex))
}

// or as arrow function (ES6+)
isHexColor = hex => typeof hex === 'string' && hex.length === 6 && !isNaN(Number('0x' + hex))

console.log(isHexColor('AABBCC'))   // true
console.log(isHexColor('AABBCC11')) // false
console.log(isHexColor('XXBBCC'))   // false
console.log(isHexColor('AAXXCC'))   // false

This answer used to throw false positives because instead of Number('0x' + hex), it used parseInt(hex, 16).
parseInt() will parse from the beginning of the string until it reaches a character that isn't included in the radix (16). This means it could parse strings like 'AAXXCC', because it starts with 'AA'.

Number(), on the other hand, will only parse if the whole string matches the radix. Now, Number() doesn't take a radix parameter, but luckily, you can prefix number literals to get a number in other radii.

Here's a table for clarification:

╭─────────────┬────────────┬────────┬───────────────────╮
│ Radix       │ Characters │ Prefix │ Will output 27    │
╞═════════════╪════════════╪════════╪═══════════════════╡
│ Binary      │ 0-1        │ 0b     │ Number('0b11011') │
│ Octal       │ 0-7        │ 0o     │ Number('0o33')    │
│ Decimal     │ 0-9        │ -      │ -                 │
│ Hexadecimal │ 0-9A-F     │ 0x     │ Number('0x1b')    │
╰─────────────┴────────────┴────────┴───────────────────╯
11
  • 9
    +1 bcs much better to read and faster to understand than a regex
    – Chris
    Commented Apr 11, 2013 at 13:42
  • 16
    @Chris 'because' is also much better to read and faster to understand than 'bcs' ;-)
    – Chris
    Commented Oct 9, 2013 at 14:12
  • 1
    @Chris: i got so used to 'bcs' for me doesnt make a difference. anyways my comment was meant as a compliment so be happy.
    – Chris
    Commented Oct 26, 2013 at 21:23
  • 12
    This is wrong: parseInt('abcZab', 16) will output number and pass the test Commented Feb 14, 2014 at 2:05
  • 1
    @fflorent Because parseInt will take "abcZab", find that "Z" is invalid (for radix 16), and ignore it and anything after it. It then takes the beginning "abc" and convert it to 2748 (which is also the result of parseInt("abcZab", 16), proving that's the logic happening). As the name implies, parseInt parses a string. Just like if you were parsing a number with units on it with a radix of 10, like parseInt("10px", 10), you'd get 10. You can see it described here: es5.github.io/#x15.1.2.2 (step 11)
    – Ian
    Commented Sep 22, 2014 at 21:25
8

This can be a complicated problem. After several attempts I came up with a fairly clean solution. Let the browswer do the the work for you.

Step 1: Create a div with border-style set to none. The div can be positioned off screen or it can be any div on your page that doesn't use the borders.

Step 2: Set the border color to an empty string. The code might look something like this:

e=document.getElementbyId('mydiv');
e.style.borderColor="";

Step 3: Set the border color to the color you aren't sure about.

e.style.borderColor=testcol;

Step 4: Check to see if the color actually got changed. If testcol is invalid, no change will occur.

col2=e.style.borderColor;
if(col2.length==0) {alert("Bad Color!");}

Step 5: Clean up after yourself by setting the color back to an empty string.

e.style.borderColor="";

The Div:

<div id="mydiv" style="border-style:none; position:absolute; left:-9999px; top:-9999px;"></div>

Now the JavaScript function:

function GoodColor(color)
{
   var color2="";
   var result=true;
   var e=document.getElementById('mydiv');
   e.style.borderColor="";
   e.style.borderColor=color;
   color2=e.style.borderColor;
   if (color2.length==0){result=false;}
   e.style.borderColor="";
   return result;
}

In this case, the function is returning a true/false answer to the question, the other option is to have it return a valid color value. Your original color value, the value from borderColor or an empty string in place of invalid colors.

3
  • 5
    IMO, this isn't a clean solution in the least Commented Sep 18, 2019 at 15:33
  • 1
    IMO, this could easily be the most complicated solution.
    – Nick Song
    Commented Jul 6, 2022 at 6:06
  • This can only be implemented in a browser environment (is not a pure-javascript solution)
    – vsync
    Commented Jul 3, 2023 at 12:40
6

If you are trying to use it in HTML Try using this pattern Directly :

 pattern="^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$"

like

<input id="hex" type="text" pattern="^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$" />

It will give a validation to match the requested format.

2

To write a good validation, I started from writing the positive and negative tests, establishing a baseline for which my validation code should work by, and mixing a few of the good answers here and my own logic, I came up with this:

/^#(([0-9A-Fa-f]{2}){3,4}|[0-9A-Fa-f]{3})$/.test(hex)

http://www.regexplained.co.uk

Tests Cases:

(hopefully covering over 90% of cases)

const isValidHex = hex => /^#(([0-9A-Fa-f]{2}){3,4}|[0-9A-Fa-f]{3})$/.test(hex);

// positive tests
[
  '#ffffff',   // 6-characters, valid range
  '#ffffff99', // 9-characters, last 2 for alpha channel
  '#fff',      // 3-characters
].forEach(c => console.log(isValidHex(c), c));

console.log('\nshould fail:\n\n');

// negative tests
[
  '#invalid',   // obviously not a color
  '#f',         // 1 character is not enough
  '#ff',        // 2 characters is not enough
  '#ffff',      // 4 characters is not enough
  '#fffff',     // 5 characters is not enough
  '#fffffff',   // 7 characters is not enough
  '#ffffff999', // 9 characters are too many
  '#ggg',       // HEX is base 16, so characters beyond "F" (16) are invalid
].forEach(c => console.log(isValidHex(c), c))

1

If you need a function to tell you if a color is valid, you might as well have it give you something useful -- the computed values of that color -- and return null when it is not a valid color. Here's my stab at a compatible (Chrome54 & MSIE11) function to get the RGBA values of a "color" in any of the formats --be it 'green', or '#FFF', or '#89abcd', or 'rgb(0,0,128)', or 'rgba( 0, 128, 255, 0.5)'.

/* getRGBA:
  Get the RGBA values of a color.
  If input is not a color, returns NULL, else returns an array of 4 values:
   red (0-255), green (0-255), blue (0-255), alpha (0-1)
*/
function getRGBA(value) {
  // get/create a 0 pixel element at the end of the document, to use to test properties against the client browser
  var e = document.getElementById('test_style_element');
  if (e == null) {
    e = document.createElement('span');
    e.id = 'test_style_element';
    e.style.width = 0;
    e.style.height = 0;
    e.style.borderWidth = 0;
    document.body.appendChild(e);
  }

  // use the browser to get the computed value of the input
  e.style.borderColor = '';
  e.style.borderColor = value;
  if (e.style.borderColor == '') return null;
  var computedStyle = window.getComputedStyle(e);
  var c
  if (typeof computedStyle.borderBottomColor != 'undefined') {
    // as always, MSIE has to make life difficult
    c = window.getComputedStyle(e).borderBottomColor;
  } else {
    c = window.getComputedStyle(e).borderColor;
  }
  var numbersAndCommas = c.replace(new RegExp('[^0-9.,]+','g'),'');
  var values = numbersAndCommas.split(',');
  for (var i = 0; i < values.length; i++)
    values[i] = Number(values[i]);
  if (values.length == 3) values.push(1);
  return values;
}
1
function validColor(color){
  var $div = $("<div>");
  $div.css("border", "1px solid "+color);
  return ($div.css("border-color")!="")
}

https://gist.github.com/dustinpoissant/22ce25c9e536bb2c5a2a363601ba261c

Note: This requires jQuery

This works for ALL color types not just hex values. It also does not append unnecessary elements to the DOM tree.

1
  • Nice and easy and works very well. Personally I added if(hexString.indexOf('#') == -1) { return false; } to check for a hash as a rudimentary check that color was a hex value Commented Mar 3, 2018 at 6:37
1

a simple solution using web api

function isHexCode(hex) {
  const validator = new Option().style;
  validator.color = hex;

  return typeof validator.color === "string" && validator.color.length > 0;
}

isHexCode("#000"); // true
isHexCode("blah"); // false
1
  • 1
    Great solution for web!
    – ngoue
    Commented May 13 at 17:00
0

Add a length check to make sure that you don't get a false positive

function isValidHex(testNum){
  let validHex = false;
  let numLength = testNum.length;
  let parsedNum = parseInt(testNum, 16);
  if(!isNan(parsedNum) && parsedNum.length===numLength){
     validHex = true;
  }
  return validHex;

}

0

I decided to try a different perspective. My rules were : 1)Arbitrarily long sequence of hex characters, 2)Usage of either "0x" or "#" at the front of a sequence, or 3)Just a hex number or string. I'm thinking back to when binhex was one of the big programs. Binhex would create really large files that could be transferred to anyplace and then made back in to whatever file it was you converted. These files would have 80 characters followed by a return. So in this function I look for returns and take them back out first. Modified the function so it looks for both the "\n" and "\r". Here is the code:

////////////////////////////////////////////////////////////////////////////////
//  isHex(). Is this a hex string/value?
//  Arguments   :   0   =   Item to test
//                  1   =   V(alue) or S(tring). Default is STRING.
////////////////////////////////////////////////////////////////////////////////
function isHex()
{
    var p = 0;
    var re1 = /(\n|\r)+/g;
    var re2 = /[\Wg-zG-Z]/;
    var re3 = /v/i;
//
//  Make sure the string is really a string.
//
    var s = arguments[0];
    if( typeof s != "string" ){ s = s.toString(); }
//
//  Check if this is a hex VALUE
//  and NOT a hex STRING.
//
    var opt = arguments[1];
    if( re3.test(opt) && (s.length % 2 > 0) ){ return "false"; }
//
//  Remove any returns. BinHex files can be megabytes in length with 80
//  column information. So we have to remove all returns first.
//
    s.replace( re1, "" );
//
//  IF they send us something with the universal "0x" or the HTML "#" on the
//  front of it - we have to FIRST move where we look at the string.
//
    if( s.substr(0,1) == "#" ){ p = 1; }
        else if( s.substr(0,2).toLowerCase() == "0x" ){ p = 2; }

   if( re2.test(s.substr(p,s.length)) ){ return "false"; }

   return "true";
}

alert("HELLO There!");
alert(isHex("abcdef"));
alert(isHex("0x83464"));
alert(isHex("#273847"));
alert(isHex("This is a test"));
alert(isHex(0x5346));

I have purposefully left the return values as strings but all you have to do is to remove the double quotes and the function will then just return TRUE or FALSE.

0

If ARGB is expected to be supported, the supported hexadecimal digits are 3, 4, 6, 8.

const isColor = (strColor) => {
  return /^#(([0-9A-Fa-f]{2}){3,4}|[0-9A-Fa-f]{3,4})$/.test(strColor)
}

Note that {2} should precede {3,4} to ensure that the 7-digit hexadecimal can be correctly checked as false.

Not the answer you're looking for? Browse other questions tagged or ask your own question.