CSS Variables (custom properties) in Pseudo-element "content" Property

Edit for clarity: CSS custom properties with integer values can be displayed in a pseudo-element's content property via a CSS counter.

div {
    --variable: 123;
}
span:after {
    counter-reset: variable var(--variable);
    content: counter(variable);
}
<div>The variable is <span></span>.</div>

.coordinates:before {
    counter-reset: x var(--x) y var(--y);
    content: 'The coordinates are (' counter(x) ', ' counter(y) ').';
}
<div class="coordinates" style="--x: 1; --y: 2"></div>

Original Answer

Got it to work using a hack involving CSS Counters. Enjoy.

div::after {
  counter-reset: mouse-x var(--mouse-x, 245) mouse-y var(--mouse-y, 245);
  content: counter(mouse-x) " / " counter(mouse-y);
}

Full code in action:

document.addEventListener('mousemove', (e) => {
  document.documentElement.style.setProperty('--mouse-x', e.clientX)
  document.documentElement.style.setProperty('--mouse-y', e.clientY)
  
  // output for explanation text
  document.querySelector('.x').innerHTML = e.clientX
  document.querySelector('.y').innerHTML = e.clientY
})
/* what I want!! */
div::after {
  counter-reset: mouse-x var(--mouse-x, 245) mouse-y var(--mouse-y, 245);
  content: counter(mouse-x) " / " counter(mouse-y);
}

/* setup and presentation styles */
div::before {
  content: 'mouse position:';
}
div {
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(calc(var(--mouse-x, 245) * 1px), calc(var(--mouse-y, 327) * 1px));
  width: 10em;
  height: 10em;
  background: #ff3b80;
  color: #fff;
  display: flex;
  flex-flow: column;
  align-items: center;
  justify-content: center;
  border-radius: 100%;
  will-change: transform;
}
body {
  margin: 2em;
  font-family: sans-serif;
}
p {
  max-width: 50%;
  min-width: 25em;
}
<!-- test case: element with pseudo element -->
<div></div>

<!-- explanation (not test case) -->
<main>
  <pre><code>div::after {
  content: var(--mouse-x) ' / ' var(--mouse-y);
}</code></pre>
  <h1>If this worked...</h1>
  <p>
    We should see something like this: <b><span class="x">245</span> / <span class="y">327</span></b> updating with the mousemove coordinates inside the pseudo <i>::after</i> element for the div.
  </p>
</main>

I'm not quite sure if I understood your question correctly, but I think here's a solution...

You can define a custom attribute to your <div> element.

<div data-position></div>

Then assign the position in this attribute with javascript:

  var position = e.clientX + " " + e.clientY
  document.querySelector("div").setAttribute('data-position', position)

Finally use the attr() CSS function in the content property of your pseudoelement.

div::after {
  content: attr(data-position);
}

And voila.


Code Snippet:

document.addEventListener('mousemove', (e) => {
  document.documentElement.style.setProperty('--mouse-x', e.clientX)
  document.documentElement.style.setProperty('--mouse-y', e.clientY)
  var position = e.clientX + "/" + e.clientY
  document.querySelector("div").setAttribute('data-position', position)
    // output for explanation text
  document.querySelector('.x').innerHTML = e.clientX
  document.querySelector('.y').innerHTML = e.clientY
})
/* what I want!! */

div::after {
  content: attr(data-position);
}
/* setup and presentation styles */

div::before {
  content: 'mouse position:';
}
div {
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(calc(var(--mouse-x, 245) * 1px), calc(var(--mouse-y, 327) * 1px));
  width: 10em;
  height: 10em;
  background: #ff3b80;
  color: #fff;
  display: flex;
  flex-flow: column;
  align-items: center;
  justify-content: center;
  border-radius: 100%;
  will-change: transform;
}
body {
  margin: 2em;
  font-family: sans-serif;
}
p {
  max-width: 50%;
  min-width: 25em;
}
<div data-position></div>
<span class="x"></span>/<span class="y"></span>

content property only allows Strings, and since you are dealign with numbers and CSS cannot cast variables, you are left with the option to create another set of variables (from JS) which will serve as the printed values, and will be of type String.

To set --mouse-x-text as String, it's not enough to cast it to that type using the old casting trick 2+"" = "2", but JSON.stringify is the only way what I know that can output a "real" string, out of the already-string value, which kind-of mean a string of a string, since CSS seems to strip the first string-layer.

document.addEventListener('mousemove', ({clientX:x, clientY:y}) => {
  const {style} = document.documentElement

  style.setProperty('--mouse-x', x)
  style.setProperty('--mouse-y', y)

  // for printing
  style.setProperty('--mouse-x-text', JSON.stringify(x+""))
  style.setProperty('--mouse-y-text', JSON.stringify(y+""))
})
body::before{
  content: "X:"var(--mouse-x-text)"  Y:"var(--mouse-y-text);
}