Reputation: 68068
For example:
AA33FF
= valid hex color
Z34FF9
= invalid hex color (has Z in it)
AA33FF11
= invalid hex color (has extra characters)
Upvotes: 182
Views: 153020
Reputation: 931
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
Upvotes: 1
Reputation: 148744
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
Upvotes: 430
Reputation: 130730
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)
(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))
Upvotes: 2
Reputation: 1
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.
Upvotes: 0
Reputation: 1467
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.
Upvotes: 0
Reputation: 1656
// 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') │
╰─────────────┴────────────┴────────┴───────────────────╯
Upvotes: 44
Reputation: 131
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;
}
Upvotes: 0
Reputation: 543
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.
Upvotes: 6
Reputation: 3428
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.
Upvotes: 1
Reputation: 2119
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;
}
Upvotes: 1
Reputation: 121
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.
Upvotes: 8