How to Add a Visual Label to Web Content

Jump to the final code ☟

The other day I saw a “New” label added to a headline by using a <div> for the label, like this:

<!-- HTML -->
<a href="prod.html">Product announcement</a>
<div class="new-item">NEW</div>
/* CSS */
.new-item {
    display: inline-flex;
    padding: 3px 5px;
    margin-left: 8px;
    background: rebeccapurple;
    border-radius: 4px;
    font-weight: 600;
    font-size: 0.8em;
    color: white;
}
Screenshot of a 'Product announcement' text link with a purple 'New' label to its right.

Hmm, while it does work, something feels not quite right about using an extra element for this. We can add content with CSS and style it, so couldn’t that work instead? Let’s try.

The “content” property and ::after pseudo-element

These old friends have excellent browser support (even IE!) and let us do two things:

Therefore we can update our new-item CSS class to append a pseudo-element, fill it with some text content, and apply it to our existing link, like this:

<a href="prod.html" class="new-item">Product announcement</a>
.new-item::after {
    content: "NEW";

    display: inline-flex;
    padding: 3px 5px;
    margin-left: 8px;
    background: rebeccapurple;
    border-radius: 4px;
    font-weight: 600;
    font-size: 0.8em;
    color: white;
}

I was worried about this being inaccessible to screen readers but it turns out support for generated content is much better than I expected1 – good enough to use this in the wild in my opinion. Because the generated content is supplementary, non-essential info, I find it acceptable if the CSS fails to load or be read out in edge cases.

Making it flexible

One disadvantage of this approach is that having content within CSS is not great for maintainability. CSS was (sensibly) designed for separating style and content, so can we use generated content but specify that content in our HTML code? Yes, we can! Say hello to data attributes. πŸ‘‹

Data attributes have multiple benefits – they can contain data (hence the name), they can be used as CSS selectors for styling, and they can easily be accessed with JavaScript via the dataset object.

Great, so how can we use them in our code? We can…

  1. Replace the new-item class with a custom data-label attribute.
  2. Use the data-label attribute as a selector to apply our CSS.
  3. Grab whatever value we give that attribute with the attr() CSS function.

Here’s how the final code would look:

<a href="prod.html" data-label="New">Product announcement</a>
[data-label]::after {
    content: attr(data-label);
    text-transform: uppercase;

    display: inline-flex;
    padding: 3px 5px;
    margin-left: 8px;
    background: rebeccapurple;
    border-radius: 4px;
    font-weight: 600;
    font-size: 0.8em;
    color: white;
}

Tadaa! No content is hard-coded in the CSS. No extra elements are added to the HTML. Control of the label is done by just editing the data-label attribute, either manually or with code.

And I added a bit of uppercase styling for good measure.

Benefits

  • Maintenance is now easier. It’s simpler to add or remove an HTML attribute than an element, especially if done programmatically. Practical example: Automatically add a data-label="New" attribute to any headline less than seven days old.
  • No need for an extra <div> (or <span>), thus reducing divitis (the “overuse of divs in HTML markup”).
  • Your code looks good to anyone inspecting it, making you look good as a developer. πŸ™‚

  1. Big thanks to Patrick Lauke for the accessibility advice. He knows his stuff. β†©οΈŽ

Leave a comment