JSFiddle - React, Tailwind, and code Playground
HTML
<p class='intro'>
This fiddle demonstrates manipulating the CSS of pseudo-elements separately and individually. It only considers the 'text' property, and only considers the ::before element, but expanding it beyond these should be obvious. The key idea demonstrated is being able to refer to each element individually.
</p>
<div class='container'></div>
<div class='container' id='c-1'></div>
<p>Controls</p>
<input type='text' id='txt' placeholder='Text'/><br/>
<input type='radio' name='which-box' value='a' checked>Top box
<input type='radio' name='which-box' value='b'>Bottom box
<br/>
<button>Change text</button>
CSS
.container {
position: relative;
height: 50px;
background-color: #eee;
border: 1px dashed #bbb;
}
#c-1 {
margin-top: 20px;
margin-bottom: 20px;
background-color: #ddd;
}
.container::before {
position: absolute;
top: 0;
left: 0;
display: block;
content: "I am a block element in the top-left corner of .container and I don't exist in the markup";
border: 1px solid #bbb;
}
p.intro { margin-bottom: 20px; }
JavaScript
$(document).ready(function() {
var index = 0, // index/UID counter for elements
myStyleSheet; // stylesheet object
// Sets the "content" attribute on the given element's
// ::before pseudo-element.
function setPseudoText($element, text) {
// FIXME: escape quotes in text
var id = $element.attr('id'),
rule,
selector = '#' + id + '::before',
index = $element.data('pseudoIndex');
if (text !== null) {
rule = selector + ' { content: "' + text + '";}';
} else {
// no-op
rule = selector + '{}';
}
if (myStyleSheet.insertRule) {
myStyleSheet.insertRule(rule, index);
}
if (myStyleSheet.deleteRule && index+1 < myStyleSheet.cssRules.length) {
myStyleSheet.deleteRule(index+1);
}
}
// create the stylesheet and get a reference to it
$('head').append(document.createElement('style'));
myStyleSheet = document.styleSheets[document.styleSheets.length-1];
// now we need to set up our containers
$('.container').each(function() {
var $c = $(this);
// if the element doesn't already have one, we need to
// set an ID
if (!$c.attr('id')) {
$c.attr('id', 'container-' + index);
}
$c.data('pseudoIndex', index);
index++;
setPseudoText($c, null);
});
// UI handlers - ignore this stuff.
var $top = $('.container').eq(0),
$bottom = $('.container').eq(1);
$('button').click(function() {
var isTopTarget = $('input:checked').val() === 'a',
text = $('input[type=text]').val(),
$target = isTopTarget? $top : $bottom;
setPseudoText($target, text);
});
});