20 CSS Neon Text Effects14 / 20

CSS + JSMIT licensed

CSS Variables Dynamic Neon Colour

One registered @property --hue drives the entire glow spectrum — text colour and every shadow layer — so a single slider retints the whole sign live. The clean-token setup front-end engineers search for.

Published

Live Demo
Try it

The code

<div class="cnt-14">
  <div class="cnt-14__stack">
    <h2 class="cnt-14__h" id="cnt-14-sign">SPECTRUM</h2>
    <label class="cnt-14__ctrl">hue
      <input id="cnt-14-range" type="range" min="0" max="360" value="200" aria-label="Neon hue">
    </label>
  </div>
</div>
.cnt-14,
.cnt-14 *,
.cnt-14 *::before,
.cnt-14 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cnt-14 ::selection {
  background: #fff;
  color: #000;
}

@property --hue {
  syntax: '<angle>';
  inherits: true;
  initial-value: 200deg;
}

.cnt-14 {
  --hue: 200deg;
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  background: radial-gradient(120% 120% at 50% 30%,#0a0a0e,#050506);
}

.cnt-14__stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 34px;
}

.cnt-14__h {
  --c: oklch(0.82 0.19 var(--hue));
  font-size: clamp(46px,12vw,116px);
  font-weight: 900;
  letter-spacing: .05em;
  color: var(--c);
  text-shadow: 0 0 5px #fff,0 0 14px var(--c),0 0 34px var(--c),0 0 72px color-mix(in oklch,var(--c) 55%,transparent);
  animation: cnt-14-cycle 12s linear infinite;
}

@keyframes cnt-14-cycle {
  to {
    --hue: 560deg;
  }
}

.cnt-14__ctrl {
  display: flex;
  align-items: center;
  gap: 14px;
  font: 12px ui-monospace,Menlo,monospace;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: #8a8a95;
}

.cnt-14__ctrl input {
  width: 220px;
  accent-color: oklch(0.82 0.19 var(--hue));
}

@media (prefers-reduced-motion: reduce) {
  .cnt-14__h {
    animation: none;
  }
}
(function(){
  var r = document.getElementById('cnt-14-range');
  var sign = document.getElementById('cnt-14-sign');
  if(!r || !sign) return;
  r.addEventListener('input', function(){
    // scrubbing overrides the idle cycle with an explicit hue
    sign.style.animation = 'none';
    sign.style.setProperty('--hue', r.value + 'deg');
  });
})();
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Neon Text Effect from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Variables Dynamic Neon Colour
Source: https://codefronts.com/motion/css-neon-text-effect/css-variables-dynamic-neon-colour/

One registered @property --hue drives the entire glow spectrum — text colour and every shadow layer — so a single slider retints the whole sign live. The clean-token setup front-end engineers search for.
## HTML
```html
<div class="cnt-14">
  <div class="cnt-14__stack">
    <h2 class="cnt-14__h" id="cnt-14-sign">SPECTRUM</h2>
    <label class="cnt-14__ctrl">hue
      <input id="cnt-14-range" type="range" min="0" max="360" value="200" aria-label="Neon hue">
    </label>
  </div>
</div>
```
## CSS
```css
.cnt-14,
.cnt-14 *,
.cnt-14 *::before,
.cnt-14 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cnt-14 ::selection {
  background: #fff;
  color: #000;
}

@property --hue {
  syntax: '<angle>';
  inherits: true;
  initial-value: 200deg;
}

.cnt-14 {
  --hue: 200deg;
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  background: radial-gradient(120% 120% at 50% 30%,#0a0a0e,#050506);
}

.cnt-14__stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 34px;
}

.cnt-14__h {
  --c: oklch(0.82 0.19 var(--hue));
  font-size: clamp(46px,12vw,116px);
  font-weight: 900;
  letter-spacing: .05em;
  color: var(--c);
  text-shadow: 0 0 5px #fff,0 0 14px var(--c),0 0 34px var(--c),0 0 72px color-mix(in oklch,var(--c) 55%,transparent);
  animation: cnt-14-cycle 12s linear infinite;
}

@keyframes cnt-14-cycle {
  to {
    --hue: 560deg;
  }
}

.cnt-14__ctrl {
  display: flex;
  align-items: center;
  gap: 14px;
  font: 12px ui-monospace,Menlo,monospace;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: #8a8a95;
}

.cnt-14__ctrl input {
  width: 220px;
  accent-color: oklch(0.82 0.19 var(--hue));
}

@media (prefers-reduced-motion: reduce) {
  .cnt-14__h {
    animation: none;
  }
}
```

## JavaScript
```js
(function(){
  var r = document.getElementById('cnt-14-range');
  var sign = document.getElementById('cnt-14-sign');
  if(!r || !sign) return;
  r.addEventListener('input', function(){
    // scrubbing overrides the idle cycle with an explicit hue
    sign.style.animation = 'none';
    sign.style.setProperty('--hue', r.value + 'deg');
  });
})();
```

How this works

A registered @property --hue (typed <angle>) is the single source of truth. The label's color and its whole text-shadow stack are built from oklch(... var(--hue)) and color-mix(), so changing that one number rotates every layer's hue in perfect sync — no per-colour rules anywhere.

Because --hue is a real typed property it can also be animated — the idle state slowly cycles the hue via a @keyframes. The one line of JS just points the range input at --hue so users can scrub it; remove the input and the CSS animation still runs.

Make it yours

  • --hue is the only knob — wire it to a slider, a scroll position, or leave the idle cycle running.
  • Lock lightness/chroma in the oklch() calls so every hue stays equally punchy.
  • Swap the cycle for a fixed brand hue by deleting the @keyframes and setting --hue once.
  • Add a second registered property (--glow-size) for an independent intensity slider.

Gotchas — read before shipping

  • Animating/transitioning a custom property requires it be registered with @property and a typed syntax — a plain --hue won't interpolate.
  • @property is the newest feature here — guard non-critical use and provide a sensible initial-value.
  • Keep the slider labelled and keyboard-operable; it's a real form control, not decoration.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Floor set by oklch(), color-mix(), @property as this demo is written. The core technique itself goes back further — Chrome 85+.

@property registration: Chrome 85+, Safari 16.4+, Firefox 128+. Without it the initial-value hue shows statically.

Techniques used in this demo

Search CodeFronts

Loading…