249

I want to create a function that will accept any old string (will usually be a single word) and from that somehow generate a hexadecimal value between #000000 and #FFFFFF, so I can use it as a colour for a HTML element.

Maybe even a shorthand hex value (e.g: #FFF) if that's less complicated. In fact, a colour from a 'web-safe' palette would be ideal.

3
  • 2
    Could give some sample input and/or links to the similar questions?
    – qw3n
    Commented Aug 6, 2010 at 17:59
  • 2
    Not an answer, but you may find the following useful: To convert a hexadecimal to an integer, use parseInt(hexstr, 10). To convert an integer to a hexadecimal, use n.toString(16), where n is a integer. Commented Aug 6, 2010 at 18:00
  • @qw3n - sample input: just short, plain old text strings... like 'Medicine', 'Surgery', 'Neurology', 'General Practice' etc. Ranging between 3 and say, 20 characters... can't find the other one but here's the java question: stackoverflow.com/questions/2464745/… @Daniel - Thanks. I need to sit down and have another serious go at this. could be useful. Commented Aug 6, 2010 at 18:42

19 Answers 19

328

Here's an adaptation of CD Sanchez' answer that consistently returns a 6-digit colour code:

const stringToColour = (str: string) => {
  let hash = 0;
  str.split('').forEach(char => {
    hash = char.charCodeAt(0) + ((hash << 5) - hash)
  })
  let colour = '#'
  for (let i = 0; i < 3; i++) {
    const value = (hash >> (i * 8)) & 0xff
    colour += value.toString(16).padStart(2, '0')
  }
  return colour
}

If you are using Eslint, you want to wrap this function in the

/* eslint-disable no-bitwise */
>> stringToColour func. definition here" <<
/* eslint-enable no-bitwise */

Usage:

stringToColour("greenish");
// -> #9bc63b

Example:

http://jsfiddle.net/sUK45/

(An alternative/simpler solution might involve returning an 'rgb(...)'-style colour code.)

7
  • 6
    This code works awesome in conjunction with NoSQL auto-generated ID's, your colour will be the same every time for the same user.
    – deviavir
    Commented Jun 26, 2014 at 20:57
  • 1
    I needed the alpha channel for transparency in my hex codes as well. This helped (adding two digits for the alpha channel at the end of my hex code): gist.github.com/lopspower/03fb1cc0ac9f32ef38f4 Commented Oct 28, 2018 at 20:10
  • @Tjorriemorrie Upvoted for pointing out that it's colour and not color. Yes, yes, it's not really on topic but it's something that's important to me (in fact when typing it originally I spelt it 'colour' both times!). Thank you.
    – Pryftan
    Commented Mar 13, 2019 at 16:43
  • Interesting that the colour is different for the same string on different browsers/oss - e.g. Chrome+Windows and Chrome+Android - my e-mail=>colour is blue on one and green on the other. Any idea why?
    – avenmore
    Commented Aug 11, 2019 at 18:51
  • 2
    Thanks! an adaptation to this to generate pastel / bright colors from a string only stackoverflow.com/a/64490863/403372 Commented Oct 22, 2020 at 21:37
242

Just porting over the Java from Compute hex color code for an arbitrary string to Javascript:

function hashCode(str) { // java String#hashCode
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
       hash = str.charCodeAt(i) + ((hash << 5) - hash);
    }
    return hash;
} 

function intToRGB(i){
    var c = (i & 0x00FFFFFF)
        .toString(16)
        .toUpperCase();

    return "00000".substring(0, 6 - c.length) + c;
}

To convert you would do:

intToRGB(hashCode(your_string))
5
  • 1
    It needs to pad the hex strings, such as: ("00" + ((this >> 24) & 0xFF).toString(16)).slice(-2) + ("00" + ((this >> 16) & 0xFF).toString(16)).slice(-2) + ("00" + ((this >> 8) & 0xFF).toString(16)).slice(-2) + ("00" + (this & 0xFF).toString(16)).slice(-2);
    – Thymine
    Commented Feb 6, 2014 at 22:38
  • 4
    I'm converting a bunch of music genre tags to background colors and this saved me a lot of time. Commented Feb 25, 2016 at 5:18
  • I wish I could convert this to php.
    – Nimitz E.
    Commented Jun 11, 2016 at 10:17
  • 15
    I have some problems with almost same colours for similar strings, for example: intToRGB(hashCode('hello1')) -> "3A019F" intToRGB(hashCode('hello2')) -> "3A01A0" And I enhance your code by adding multiplication for final hash value: return 100 * hash;
    – SirWojtek
    Commented Aug 24, 2017 at 1:43
  • Don't forget to add '#' like return "#" + "00000".substring(0, 6 - c.length) + c; Commented Mar 21, 2019 at 19:51
76

I wanted similar richness in colors for HTML elements, I was surprised to find that CSS now supports hsl() colors, so a full solution for me is below:

Also see How to automatically generate N "distinct" colors? for more alternatives more similar to this.

Edit: updating based on @zei's version (with american spelling)

var stringToColor = (string, saturation = 100, lightness = 75) => {
  let hash = 0;
  for (let i = 0; i < string.length; i++) {
hash = string.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
  }
  return `hsl(${(hash % 360)}, ${saturation}%, ${lightness}%)`;
}


// For the sample on stackoverflow
function colorByHashCode(value) {
return "<span style='color:" + stringToColor(value) + "'>" + value + "</span>";
}

document.body.innerHTML = [
  "javascript",
  "is",
  "nice",
].map(colorByHashCode).join("<br/>");
span {
  font-size: 50px;
  font-weight: 800;
}

In HSL its Hue, Saturation, Lightness. So the hue between 0-359 will get all colors, saturation is how rich you want the color, 100% works for me. And Lightness determines the deepness, 50% is normal, 25% is dark colors, 75% is pastel. I have 30% because it fit with my color scheme best.

8
  • 3
    A very versatile solution.
    – MastaBaba
    Commented May 18, 2015 at 15:02
  • 2
    Thx for sharing a solution, where you can decide how colorful the colors should be! Commented May 28, 2016 at 12:22
  • @haykam Thanks for making it into a snippet!
    – Thymine
    Commented Oct 15, 2018 at 17:59
  • 1
    This solution returns too little colors, won't do. Commented Mar 20, 2019 at 15:46
  • 1
    @cbreezier that is because this uses the same hash function it appears. Feel free to change the hash function to something else, multiply by a large prime number and/or XOR with large prime number should move it around. But this example is aiming for a range of 360 colors of a similar tone, yes duplicates will happen, cheers
    – Thymine
    Commented Sep 4, 2023 at 22:25
43

Here is my 2021 version with Reduce Function and HSL Color.

function getBackgroundColor(stringInput) {
    let stringUniqueHash = [...stringInput].reduce((acc, char) => {
        return char.charCodeAt(0) + ((acc << 5) - acc);
    }, 0);
    return `hsl(${stringUniqueHash % 360}, 95%, 35%)`;
}
1
  • Haha! How could I miss that answer? Pretty similar to the solution I came up with ;-) Commented Aug 29, 2021 at 0:17
18

Using the hashCode as in Cristian Sanchez's answer with hsl and modern javascript, you can create a color picker with good contrast like this:

function hashCode(str) {
  let hash = 0;
  for (var i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
  }
  return hash;
}

function pickColor(str) {
  return `hsl(${hashCode(str) % 360}, 100%, 80%)`;
}

one.style.backgroundColor = pickColor(one.innerText)
two.style.backgroundColor = pickColor(two.innerText)
div {
  padding: 10px;
}
<div id="one">One</div>
<div id="two">Two</div>

Since it's hsl, you can scale luminance to get the contrast you're looking for.

function hashCode(str) {
  let hash = 0;
  for (var i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
  }
  return hash;
}

function pickColor(str) {
  // Note the last value here is now 50% instead of 80%
  return `hsl(${hashCode(str) % 360}, 100%, 50%)`;
}

one.style.backgroundColor = pickColor(one.innerText)
two.style.backgroundColor = pickColor(two.innerText)
div {
  color: white;
  padding: 10px;
}
<div id="one">One</div>
<div id="two">Two</div>

10

I find that generating random colors tends to create colors that do not have enough contrast for my taste. The easiest way I have found to get around that is to pre-populate a list of very different colors. For every new string, assign the next color in the list:

// Takes any string and converts it into a #RRGGBB color.
var StringToColor = (function(){
    var instance = null;

    return {
    next: function stringToColor(str) {
        if(instance === null) {
            instance = {};
            instance.stringToColorHash = {};
            instance.nextVeryDifferntColorIdx = 0;
            instance.veryDifferentColors = ["#000000","#00FF00","#0000FF","#FF0000","#01FFFE","#FFA6FE","#FFDB66","#006401","#010067","#95003A","#007DB5","#FF00F6","#FFEEE8","#774D00","#90FB92","#0076FF","#D5FF00","#FF937E","#6A826C","#FF029D","#FE8900","#7A4782","#7E2DD2","#85A900","#FF0056","#A42400","#00AE7E","#683D3B","#BDC6FF","#263400","#BDD393","#00B917","#9E008E","#001544","#C28C9F","#FF74A3","#01D0FF","#004754","#E56FFE","#788231","#0E4CA1","#91D0CB","#BE9970","#968AE8","#BB8800","#43002C","#DEFF74","#00FFC6","#FFE502","#620E00","#008F9C","#98FF52","#7544B1","#B500FF","#00FF78","#FF6E41","#005F39","#6B6882","#5FAD4E","#A75740","#A5FFD2","#FFB167","#009BFF","#E85EBE"];
        }

        if(!instance.stringToColorHash[str])
            instance.stringToColorHash[str] = instance.veryDifferentColors[instance.nextVeryDifferntColorIdx++];

            return instance.stringToColorHash[str];
        }
    }
})();

// Get a new color for each string
StringToColor.next("get first color");
StringToColor.next("get second color");

// Will return the same color as the first time
StringToColor.next("get first color");

While this has a limit to only 64 colors, I find most humans can't really tell the difference after that anyway. I suppose you could always add more colors.

While this code uses hard-coded colors, you are at least guaranteed to know during development exactly how much contrast you will see between colors in production.

Color list has been lifted from this SO answer, there are other lists with more colors.

2
  • Fwiw there's an algorithm out there to determine contrast. I wrote something with it years ago (but in C). Too much going on to worry about it and it's an old answer anyway but figured I'd point out that there is a way to determine contrast.
    – Pryftan
    Commented Mar 13, 2019 at 16:46
  • supplement: to wrap colours back to first after all are used, replace the 2nd if with: if(!instance.stringToColorHash[str]) { instance.nextVeryDifferntColorIdx++; instance.nextVeryDifferntColorIdx %= instance.veryDifferentColors.length; instance.stringToColorHash[str] = instance.veryDifferentColors[instance.nextVeryDifferntColorIdx]; }
    – MoonLite
    Commented Nov 9, 2020 at 17:08
7

If your inputs are not different enough for a simple hash to use the entire color spectrum, you can use a seeded random number generator instead of a hash function.

I'm using the color coder from Joe Freeman's answer, and David Bau's seeded random number generator.

function stringToColour(str) {
    Math.seedrandom(str);
    var rand = Math.random() * Math.pow(255,3);
    Math.seedrandom(); // don't leave a non-random seed in the generator
    for (var i = 0, colour = "#"; i < 3; colour += ("00" + ((rand >> i++ * 8) & 0xFF).toString(16)).slice(-2));
    return colour;
}
7

I have opened a pull request to Please.js that allows generating a color from a hash.

You can map the string to a color like so:

const color = Please.make_color({
    from_hash: "any string goes here"
});

For example, "any string goes here" will return as "#47291b"
and "another!" returns as "#1f0c3d"

2
  • Really cool thanks for adding that. Hi wanting to generate circles with letters in based on a name like Google inbox does:)
    – marcus7777
    Commented Nov 18, 2016 at 10:22
  • when I saw this answer, I thought, perfect, now I have to think about the color schema so it doesn't generate very random colors, then I read about the Please.js make_color options and it put a beautiful smile in my face.
    – panchicore
    Commented Feb 22, 2019 at 23:57
7

Javascript Solution inspired by Aslam's solution but returns a color in hex color code

/**
 * 
 * @param {String} - stringInput - 'xyz'
 * @returns {String} - color in hex color code - '#ae6204'
 */
function getBackgroundColor(stringInput) {
    const h = [...stringInput].reduce((acc, char) => {
        return char.charCodeAt(0) + ((acc << 5) - acc);
    }, 0);
    const s = 95, l = 35 / 100;
    const a = s * Math.min(l, 1 - l) / 100;
    const f = n => {
        const k = (n + h / 30) % 12;
        const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
        return Math.round(255 * color).toString(16).padStart(2, '0');   // convert to Hex and prefix "0" if needed
    };
    return `#${f(0)}${f(8)}${f(4)}`;
}
3
  • This is really nice. May I use this code? Commented Mar 30, 2022 at 10:58
  • 1
    of course, you can. Commented Mar 31, 2022 at 11:07
  • For those you encounter that some hashes turn negative and the color is always gray. It turns our js converts to int32 and stuff, see SA. So I have changes the line from return char.charCodeAt(0) + ((acc << 5) - acc); to return char.charCodeAt(0) + ((acc << 5 >>> 0) - acc);
    – Leon
    Commented Jul 3, 2022 at 17:49
5

Yet another solution for random colors:

function colorize(str) {
    for (var i = 0, hash = 0; i < str.length; hash = str.charCodeAt(i++) + ((hash << 5) - hash));
    color = Math.floor(Math.abs((Math.sin(hash) * 10000) % 1 * 16777216)).toString(16);
    return '#' + Array(6 - color.length + 1).join('0') + color;
}

It's a mixed of things that does the job for me. I used JFreeman Hash function (also an answer in this thread) and Asykäri pseudo random function from here and some padding and math from myself.

I doubt the function produces evenly distributed colors, though it looks nice and does that what it should do.

3
  • '0'.repeat(...) is not valid javascript
    – kikito
    Commented May 21, 2014 at 16:20
  • @kikito fair enough, probably I had the prototype extended somehow (JQuery?). Anyway, I've edited the function so it's javascript only... thanks for pointing that out.
    – estani
    Commented May 22, 2014 at 13:29
  • @kikito it's valid ES6, though using it would be neglecting cross-browser compatibility. Commented Jul 24, 2016 at 20:58
4

Here's a solution I came up with to generate aesthetically pleasing pastel colours based on an input string. It uses the first two chars of the string as a random seed, then generates R/G/B based on that seed.

It could be easily extended so that the seed is the XOR of all chars in the string, rather than just the first two.

Inspired by David Crow's answer here: Algorithm to randomly generate an aesthetically-pleasing color palette

//magic to convert strings to a nice pastel colour based on first two chars
//
// every string with the same first two chars will generate the same pastel colour
function pastel_colour(input_str) {

    //TODO: adjust base colour values below based on theme
    var baseRed = 128;
    var baseGreen = 128;
    var baseBlue = 128;

    //lazy seeded random hack to get values from 0 - 256
    //for seed just take bitwise XOR of first two chars
    var seed = input_str.charCodeAt(0) ^ input_str.charCodeAt(1);
    var rand_1 = Math.abs((Math.sin(seed++) * 10000)) % 256;
    var rand_2 = Math.abs((Math.sin(seed++) * 10000)) % 256;
    var rand_3 = Math.abs((Math.sin(seed++) * 10000)) % 256;

    //build colour
    var red = Math.round((rand_1 + baseRed) / 2);
    var green = Math.round((rand_2 + baseGreen) / 2);
    var blue = Math.round((rand_3 + baseBlue) / 2);

    return { red: red, green: green, blue: blue };
}

GIST is here: https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd

2
  • I must say that this is a really odd way of doing it. It kind of works but there aren't very many colors available. XOR of the first two colors makes no distinction of order so there are just combinations of letters. A simple addition I did to increase the number of colors was var seed = 0; for (var i in input_str) { seed ^= i; }
    – Gussoh
    Commented Sep 30, 2015 at 12:59
  • Yes, it really depends how many colours you'd like to generate. I recall in this instance I was creating different panes in a UI and wanted a limited number of colours rather than a rainbow :) Commented Oct 19, 2018 at 4:49
3

2024 version - Plain and simple TypeScript arrow function that returns HSL color.

const stringToColor = (value: string) => {
  let hash = 0;
  for (let i = 0; i < value.length; i++) {
    hash = value.charCodeAt(i) + ((hash << 5) - hash);
  }

  return `hsl(${hash % 360}, 85%, 35%)`;
};

1

Here is another try:

function stringToColor(str){
  var hash = 0;
  for(var i=0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 3) - hash);
  }
  var color = Math.abs(hash).toString(16).substring(0, 6);

  return "#" + '000000'.substring(0, 6 - color.length) + color;
}
1

All you really need is a good hash function. On node, I just use

const crypto = require('crypto');
function strToColor(str) {
    return '#' + crypto.createHash('md5').update(str).digest('hex').substr(0, 6);
}
1

After having a look at the rather code intensive and rather old answers, I thought I'd review this issue from a 2021 standpoint just for fun, hope it is of use to anyone. Having the HSL color model and the crypto API implemented in pretty much all browsers (except IE of course) today, it could be solved as simple as that:

async function getColor(text, minLightness = 40, maxLightness = 80, minSaturation = 30, maxSaturation = 100) {
  let hash = await window.crypto.subtle.digest("SHA-1", new TextEncoder().encode(text));
  hash = new Uint8Array(hash).join("").slice(16);

  return "hsl(" + (hash % 360) + ", " + (hash % (maxSaturation - minSaturation) + minSaturation) + "%, " + (hash % (maxLightness - minLightness) + minLightness) + "%)";
}

function generateColor() {
  getColor(document.getElementById("text-input").value).then(color => document.querySelector(".swatch").style.backgroundColor = color);
}
input {
  padding: 5px;
}

.swatch {
  margin-left: 10px;
  width: 28px;
  height: 28px;
  background-color: white;
  border: 1px solid gray;
}

.flex {
  display: flex;
}
<html>

<body>
  <div class="flex">
    <form>
      <input id="text-input" type="text" onInput="generateColor()" placeholder="Type here"></input>
    </form>
    <div class="swatch"></div>
  </div>
</body>

</html>

This should be way faster than generating hashes manually, and also offers a way to define saturation and lightness in case you don't want colors that are too flat or too bright or too dark (e.g. if you want to write text on those colors).

0

I have a situation where i want to display a background based on the username of the user and display the username's first letter on top. i used the belove code for that it worked well for me

var stringToColour = function (str) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
  hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
var colour = '#';
for (var i = 0; i < 3; i++) {
  var value = (hash >> (i * 8)) & 0xff;
  colour += ('00' + value.toString(16)).substr(-2);
}
return colour;}

To find the appropriate colour you can use

function lightOrDark(color) {
// Check the format of the color, HEX or RGB?
if (color.match(/^rgb/)) {
  // If HEX --> store the red, green, blue values in separate variables
  color = color.match(
    /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/,
  );

  var r = color[1];
  var g = color[2];
  var b = color[3];
} else {
  // If RGB --> Convert it to HEX: http://gist.github.com/983661
  color = +(
    '0x' + color.slice(1).replace(color.length < 5 && /./g, '$&$&')
  );

  r = color >> 16;
  g = (color >> 8) & 255;
  b = color & 255;
}

// HSP equation from http://alienryderflex.com/hsp.html
var hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));

// Using the HSP value, determine whether the color is light or dark
if (hsp > 127.5) {
  return 'light';
} else {
  return 'dark';
}

}

-1

This function does the trick. It's an adaptation of this, fairly longer implementation this repo ..

const color = (str) => {
    let rgb = [];
    // Changing non-hexadecimal characters to 0
    str = [...str].map(c => (/[0-9A-Fa-f]/g.test(c)) ? c : 0).join('');
    // Padding string with zeroes until it adds up to 3
    while (str.length % 3) str += '0';

    // Dividing string into 3 equally large arrays
    for (i = 0; i < str.length; i += str.length / 3)
        rgb.push(str.slice(i, i + str.length / 3));

    // Formatting a hex color from the first two letters of each portion
    return `#${rgb.map(string => string.slice(0, 2)).join('')}`;
}
1
  • This generates a lot of very dark values.
    – Langdon
    Commented Jan 3, 2020 at 21:23
-1

my code is for Java.

Thanks for all.

public static int getColorFromText(String text)
    {
        if(text == null || text.length() < 1)
            return Color.BLACK;

        int hash = 0;

        for (int i = 0; i < text.length(); i++)
        {
            hash = text.charAt(i) + ((hash << 5) - hash);
        }

        int c = (hash & 0x00FFFFFF);
        c = c - 16777216;

        return c;
    }
-8

I convert this in one line for Python

import hashlib

hash = hashlib.sha1(b'[email protected]').hexdigest()

print("#" + hash[0:6])

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