Open demo

CSS code

HTML
<div><span class="lbl">Neon readout</span>
<div class="neon" data-neon><span class="sr-only" data-say>Current time</span><span aria-hidden="true" data-show="hms">--:--:--</span></div></div>
<div><span class="lbl">Segmented</span>
<div class="seg" data-neon><span class="sr-only" data-say>Current time</span><span aria-hidden="true" data-show="hms">--:--:--</span></div></div>
<div><span class="lbl">Minute ring</span>
<div class="ring" data-neon><span class="sr-only" data-say>Current time</span><b aria-hidden="true" data-show="hm">--:--</b></div></div>
CSS
/* Neon clocks for dark interfaces. The script fills [data-show] (hms, hm) in each [data-neon] root and sets
   --p (0-360deg, the progress through the current minute), which the ring draws as a conic gradient. */
.neon{font-size:3.4rem;font-weight:600;color:#22d3ee;font-variant-numeric:tabular-nums;
  text-shadow:0 0 8px rgba(34,211,238,.85),0 0 26px rgba(34,211,238,.5)}
.seg{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:3rem;color:#f472b6;
  letter-spacing:.08em;font-variant-numeric:tabular-nums;text-shadow:0 0 10px rgba(244,114,182,.6)}
.ring{--ring-fill:#22d3ee;--ring-track:#1c2431;--ring-ground:#0b0f16;
  width:150px;height:150px;border-radius:50%;display:grid;place-items:center;position:relative;color:#e6e9ef;
  background:conic-gradient(var(--ring-fill) var(--p,0deg),var(--ring-track) 0)}
.ring::before{content:"";position:absolute;inset:9px;border-radius:50%;background:var(--ring-ground)}
.ring b{position:relative;font-size:1.5rem;font-weight:600;font-variant-numeric:tabular-nums}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
JavaScript
// Neon clocks. Once a second (re-timed to the second boundary) every [data-neon] root gets the time in its
// [data-show] elements and --p for the minute ring. The visually hidden [data-say] text changes once a minute.
(function () {
  var roots = document.querySelectorAll('[data-neon]');
  if (!roots.length) return;
  var lastMinute = -1;
  function p2(n) { return String(n).padStart(2, '0'); }
  function tick() {
    var d = new Date(), H = d.getHours(), M = d.getMinutes(), S = d.getSeconds();
    var out = { hms: p2(H) + ':' + p2(M) + ':' + p2(S), hm: p2(H) + ':' + p2(M) };
    var newMinute = M !== lastMinute; lastMinute = M;
    roots.forEach(function (root) {
      root.style.setProperty('--p', S * 6 + 'deg');
      root.querySelectorAll('[data-show]').forEach(function (el) { el.textContent = out[el.getAttribute('data-show')]; });
      var say = root.querySelector('[data-say]');
      if (say && newMinute) say.textContent = 'Current time ' + out.hm;
    });
    setTimeout(tick, 1000 - Date.now() % 1000);
  }
  tick();
})();

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Neon readout</span>
<div class="neon fw-semibold" data-neon><span class="visually-hidden" data-say>Current time</span><span aria-hidden="true" data-show="hms">--:--:--</span></div></div>
<div><span class="lbl">Segmented</span>
<div class="seg font-monospace" data-neon><span class="visually-hidden" data-say>Current time</span><span aria-hidden="true" data-show="hms">--:--:--</span></div></div>
<div><span class="lbl">Minute ring</span>
<div class="ring d-grid position-relative rounded-circle" data-neon><span class="visually-hidden" data-say>Current time</span><b class="position-relative fw-semibold" aria-hidden="true" data-show="hm">--:--</b></div></div>
CSS
/* Neon clocks with Bootstrap utilities (.fw-semibold, .font-monospace, .rounded-circle, .d-grid). The glow and the
   conic-gradient ring are custom CSS; the script sets --p (the progress through the minute) on each [data-neon] root. */
.neon{font-size:3.4rem;color:#22d3ee;font-variant-numeric:tabular-nums;
  text-shadow:0 0 8px rgba(34,211,238,.85),0 0 26px rgba(34,211,238,.5)}
.seg{--bs-font-monospace:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:3rem;color:#f472b6;
  letter-spacing:.08em;font-variant-numeric:tabular-nums;text-shadow:0 0 10px rgba(244,114,182,.6)}
.ring{--ring-fill:#22d3ee;--ring-track:#1c2431;--ring-ground:#0b0f16;width:150px;height:150px;place-items:center;color:#e6e9ef;
  background:conic-gradient(var(--ring-fill) var(--p,0deg),var(--ring-track) 0)}
.ring::before{content:"";position:absolute;inset:9px;border-radius:50%;background:var(--ring-ground)}
.ring b{font-size:1.5rem;font-variant-numeric:tabular-nums}
JavaScript
// Neon clocks. Once a second (re-timed to the second boundary) every [data-neon] root gets the time in its
// [data-show] elements and --p for the minute ring. The visually hidden [data-say] text changes once a minute.
(function () {
  var roots = document.querySelectorAll('[data-neon]');
  if (!roots.length) return;
  var lastMinute = -1;
  function p2(n) { return String(n).padStart(2, '0'); }
  function tick() {
    var d = new Date(), H = d.getHours(), M = d.getMinutes(), S = d.getSeconds();
    var out = { hms: p2(H) + ':' + p2(M) + ':' + p2(S), hm: p2(H) + ':' + p2(M) };
    var newMinute = M !== lastMinute; lastMinute = M;
    roots.forEach(function (root) {
      root.style.setProperty('--p', S * 6 + 'deg');
      root.querySelectorAll('[data-show]').forEach(function (el) { el.textContent = out[el.getAttribute('data-show')]; });
      var say = root.querySelector('[data-say]');
      if (say && newMinute) say.textContent = 'Current time ' + out.hm;
    });
    setTimeout(tick, 1000 - Date.now() % 1000);
  }
  tick();
})();

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#8b95a7] uppercase">Neon readout</span>
<div class="text-[3.4rem] font-semibold text-[#22d3ee] tabular-nums text-shadow-[0_0_8px_rgba(34,211,238,.85),0_0_26px_rgba(34,211,238,.5)]" data-neon><span class="sr-only" data-say>Current time</span><span aria-hidden="true" data-show="hms">--:--:--</span></div></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#8b95a7] uppercase">Segmented</span>
<div class="font-[ui-monospace,SFMono-Regular,Menlo,monospace] text-[3rem] tracking-[.08em] text-[#f472b6] tabular-nums text-shadow-[0_0_10px_rgba(244,114,182,.6)]" data-neon><span class="sr-only" data-say>Current time</span><span aria-hidden="true" data-show="hms">--:--:--</span></div></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#8b95a7] uppercase">Minute ring</span>
<div class="relative grid size-[150px] place-items-center rounded-full bg-[conic-gradient(#22d3ee_var(--p,0deg),#1c2431_0)] text-[#e6e9ef] before:absolute before:inset-[9px] before:rounded-full before:bg-[#0b0f16]" data-neon><span class="sr-only" data-say>Current time</span><b class="relative text-[1.5rem] font-semibold tabular-nums" aria-hidden="true" data-show="hm">--:--</b></div></div>
JavaScript
// Neon clocks. Once a second (re-timed to the second boundary) every [data-neon] root gets the time in its
// [data-show] elements and --p for the minute ring. The visually hidden [data-say] text changes once a minute.
(function () {
  var roots = document.querySelectorAll('[data-neon]');
  if (!roots.length) return;
  var lastMinute = -1;
  function p2(n) { return String(n).padStart(2, '0'); }
  function tick() {
    var d = new Date(), H = d.getHours(), M = d.getMinutes(), S = d.getSeconds();
    var out = { hms: p2(H) + ':' + p2(M) + ':' + p2(S), hm: p2(H) + ':' + p2(M) };
    var newMinute = M !== lastMinute; lastMinute = M;
    roots.forEach(function (root) {
      root.style.setProperty('--p', S * 6 + 'deg');
      root.querySelectorAll('[data-show]').forEach(function (el) { el.textContent = out[el.getAttribute('data-show')]; });
      var say = root.querySelector('[data-say]');
      if (say && newMinute) say.textContent = 'Current time ' + out.hm;
    });
    setTimeout(tick, 1000 - Date.now() % 1000);
  }
  tick();
})();

About this set

Three clocks designed for dark interfaces. The neon readout is a cyan 24-hour time with a two-layer text-shadow glow, for a hero, a gaming or music interface, or a wall display. The segmented display uses a pink monospaced face with letter spacing and a softer glow, for an LED or instrument-panel look. The minute ring is a 150 pixel circle with the time in the centre and a cyan arc that fills as the current minute passes, then starts again. The ring is a conic-gradient whose angle comes from a –p custom property, with a pseudo-element covering the middle to leave a 9 pixel track, so there is no SVG and no canvas. One short vanilla script updates every [data-neon] element once a second, re-timed to the second boundary, writing the time into its data-show elements and setting –p for the ring. All three keep tabular figures so the digits hold their positions. The Bootstrap version uses font, weight and shape utilities with the glow in a small stylesheet, and the Tailwind version uses text-shadow and conic-gradient arbitrary values.

What’s included

  • Cyan neon readout with a layered glow
  • Pink monospaced segmented display
  • Minute ring drawn with a conic-gradient and one custom property
  • No SVG, canvas or image assets
  • Captions lightened to pass contrast on the dark background

Accessibility

The visible times are aria-hidden, and each clock carries visually hidden text such as "Current time 21:55" that changes once a minute and is not a live region, so screen readers are not interrupted. The demo captions were lightened to reach 4.5:1 on the near-black ground. Nothing animates; the ring advances in one-second steps.

Customise it

Change the colours and glows on .neon and .seg, and --ring-fill, --ring-track and --ring-ground on .ring, in plain CSS and Bootstrap. In Tailwind edit the text-, text-shadow- and bg-[conic-gradient(...)] utilities.