blog

Using CSS variables (custom properties) as content property value

CSS custom properties can be used to set values on any other CSS property. Combining it with content property to set some content in pseudo-element works as you would expect it. As long as content value is of type String that is (more on that follows).

// This works
:root
{
--copy: 'hello world';
}

body::before {
content: var(--copy);
}

But what if you want to set property value using JavaScript?

document.body.style.setProperty('--copy', 'hello');
// This does not work :(
body::before
{
content: var(--copy);
}

I was puzzled until landing on this SO question and seeing this answer.

Turns out, if you use setProperty to set CSS custom property, result will look something like this:

<body style="--copy:hello;">

Without quotation marks, the parser is unable to determine that value is a string so it won’t render. And simply passing an actual string to setProperty is not enough. What’s worse, using a second value in var as fallback also won’t work since --copy is defined (just with an invalid value).

// This still does not work :(
body::before
{
content: var(--copy, 'fallback');
}

Instead, you have to do it like this:

document.body.style.setProperty('--copy', `'hello'`);

Notice backticks around the string. This way, quotation marks make their way into an inline style declaration and everything works. Using "'" + 'hello' + '"' is another valid approach but I find template literals cleaner.

Note about numbers

If the value custom property holds is of type String is will just work. But for numbers, we need to combine it with CSS counter like so:

:root {
--x: 123;
}

div:before {
counter-reset: variable var(--x);
content: counter(variable);
}

Great trick from that same StackOverflow topic.