![Cover image for joseph_appsmith](/sites/default/files/styles/cover_avatar/public/banner.png?itok=6l-h5kZf)
Colored tags, sometimes called pills or chips, are a great way to show a list of values instead of using plain text. It adds color to the UI, and it makes it easier for users to scan through data because the colors are repeatable for each value. It's similar to conditional formatting, but for a field containing a list of values.
Here's one example of how Airtable uses tags:
In this guide, I'll be showing how to generate colored tags using JavaScript, and display them in various widgets. I'll be exploring a few different methods of adding color using JavaScript, and using template literals to generate the HTML to render the tags.
Tag Structure
First let's look at the basic HTML structure of a tag. It's not much more than a single span or div with a border radius and background color. You could also use a button or anchor tag if you wanted to add some kind of interaction, but for this example I'll be keeping it simple.
Here's a span with a little bit of CSS to make it look like a tag.
<span>Active</span>
<style>
span{
background-color: #ef7541;
padding: 2px 8px;
border-radius: 50vh;
font-size: 0.8em;
font-family: sans-serif
}
</style>
And here it is displayed in an Iframe widget. You could also use a custom widget.
Text widgets can also display HTML tags, but the styles have to be inline, or inside the HTML tags.
<span style="background-color: #ef7541; padding: 2px 8px; border-radius: 50vh; font-size: 0.8em; font-family: sans-serif;">Active</span>
Either of these options could also be used inside a list widget, so there are several different options for displaying the HTML. Now let's look at how to create the markup dynamically for a list of values.
List to Tags
Let's say we have a list of tags for this post in an array:
tags: [ "javascript", "design", "iframe", "custom widget" ]
With the map array method, we can loop over the data and use a template literal to return an array of tags.
tagValues: [ "javascript", "design", "iframe", "custom widget" ],
coloredTags(){
return this.tagValues.map(tag=>`<span style="
background-color: #ef7541;
padding: 2px 8px;
border-radius: 50vh;
font-size: 0.8em;
font-family:
sans-serif;
">${tag}</span>`).join("")
}
Ok, generating the tags dynamically is pretty easy. Now lets add different colors for each tag.
Adding Color
First we'll look at adding a config object to map a short list of tags to specific colors. Using an object will allow passing the tag name dynamically and accessing the color assigned to that property.
export default {
tagValues: [ "javascript", "design", "iframe", "custom widget" ],
colorObj: {
javascript: "#e15615",
design: "#ffcc01",
iframe: "#063289",
"custom widget": "#0ec54c"
},
coloredTags(){
return this.tagValues.map(tag=>`<span style="
background-color: ${this.colorObj[tag]};
color: white;
padding: 2px 8px;
border-radius: 50vh;
font-size: 0.8em;
font-family:
sans-serif;
">${tag}</span>`).join("")
}
}
This works well when you have a fixed, predictable list of tags. But what if you want to color any word with a random color? And what if you want the color to be the same for each word, every time? That's where things get interesting!
Automatically Assigning Colors
Picking the colors automatically is a much better approach when you have a huge list of values, or no way to know the full list of values ahead of time. However, it comes with a few challenges. Let's decide on the design criteria first though, and then we'll break the problem into pieces.
Design Criteria
- The colors should be automatically assigned for any random string
- The color should be repeatable for the same string each time the function runs
- The color should have good contrast with black text (or white, whichever you choose)
- The color should be easy to tell apart from colors returned for other strings
The first step is to choose a fixed list of colors to select from. I got some help from one of our designers on this one (Thanks Taras!)
colors:["#DA0862","#E3005D","#E90047","#EC0A28","#EB1700","#EA2500","#E63100","#DF3D00","#D35100","#CB5E00","#BF6D00","#B07000","#A17A00","#8F8000","#777700","#659400","#4E9B00","#1E9F00","#00A000","#00A21A","#00A43B","#00A653","#00A869","#00A87F","#00A693","#00A2A7","#00A0B3","#009FBD","#009AC9","#0094D4","#008CF0","#0084FF","#007CFF","#0072FF","#2D6BFF","#4E63FF","#625BFF","#724FFF","#7F49F8","#8E43E3","#9D3DD8","#AA36CA","#B52FB8","#C126A7","#CA1D94","#D31580"];
And here's the same array of colors displayed as a linear gradient in the background of a container widget.
Next, we need a function that takes a tag string as an input and returns one of these colors. And it has to be repeatable, not actually random, just automatically assigned.
If the tag string was a number, we could just use that (or some multiple of it) to pick a color from the array by its index. So we have to convert the string to a number first. Each character has a corresponding character code, and those can be summed to give each string an equivalent number.
This snippet returns the sum of the character codes for the letters in a given tag:
strToNum(inputStr="javascript"){
const letterArr = inputStr.split("");
let total = 0;
letterArr.forEach(letter => total = total + letter.charCodeAt());
return total
}
// returns 1079
Now, 1079 is way outside the range of 46 colors in our color array, but we can use the modulus operator to divide this number by 46 and get the remainder- a value we know will be in the range of 0-45, to select a color from the array.
Here's the function updated to use reduce, and then select the corresponding color.
strToNum(inputStr="javascript"){
const stringNum = [...inputStr].reduce((acc, char) => (acc + char.charCodeAt(0)) % 46, 0);
return this.colors[stringNum]
}
Combining this with the template literal from earlier, we can now map over a list of tags and return spans of tags with automatically assigned, and repeatable colors!
tagValues: [ "javascript", "design", "iframe", "custom widget" ],
listToTags(list=this.tagValues){
return list.map(tag=>{
const color = this.strToNum(tag);
return `<span style="
background-color: ${color};
color: white;
padding: 2px 8px;
border-radius: 50vh;
font-size: 0.8em;
font-family:
sans-serif;
">${tag}</span>`
}).join("")
},
strToNum(inputStr="javascript"){
const stringNum = [...inputStr].reduce((acc, char) => (acc + char.charCodeAt(0)) % 46, 0);
return this.colors[stringNum]
},
Conclusion
Tags are a great way to add some style to your app, and they are pretty easy to create with a little HTML and JavaScript. You can hard code colors when you have a fix list of values, or automatically assign colors based on the input string.
Bonus Tip: Using the same approach to generate SVGs has even more advantages, and options for other widgets to display them. An SVG is a type of HTML tag, but unlike other tags, it can also be a stand-alone image file. This means you can programmatically generate images and display them in an image widget, table widget cell, or even a container background!