36 CSS Search Bars
09 / 36

All 36 in 36 CSS Search Bars

  1. 01Command Palette Cmd+K Search Bar
  2. 02Algolia-Style Instant Search with Highlighted Results Dropdown
  3. 03E-Commerce Product Search Bar with Category Scope Dropdown
  4. 04Header Navbar Integrated Sticky Search Bar
  5. 05SaaS Dashboard Command Search with Recent and Suggested
  6. 06Minimal CSS Search Bar with Animated Underline
  7. 07CSS Rounded Pill Search Bar with Submit Button
  8. 08Glassmorphism CSS Search Bar (Backdrop Blur)
  9. 09Neon Glow CSS Search Bar (Cyberpunk)
  10. 10CSS Search Bar with Animated Caret Highlight
  11. 11CSS Search Bar with Voice Input Microphone Button
  12. 12CSS Search Bar with Loading Spinner Indicator
  13. 13CSS Search Bar with Clear Button (X on Type)
  14. 14Animated Expanding CSS Search Bar on Focus
  15. 15CSS Search Bar with Autocomplete Suggestions Dropdown
  16. 16CSS Search Bar with Keyboard Shortcut Hint (Cmd K / Ctrl K)
  17. 17CSS Search Bar with Filter Chip Tags
  18. 18CSS Search Bar with Recent Searches Dropdown
  19. 19CSS Search Bar with Rotating Placeholder Text
  20. 20CSS People Search Bar with Avatar Chips
  21. 21Neo-Brutalist CSS Search Bar with Offset Stamp
  22. 22Compact Toolbar CSS Search Bar (Docs / Wiki)
  23. 23Hero Section CSS Search Bar with CTA
  24. 24CSS Search Bar with Side Category Indicator
  25. 25Floating CSS Search Bar with Drop Shadow (Elevated)
  26. 26CSS Search + Filter Sidebar Combo Bar
  27. 27CSS Search Bar with Inline Loading Progress Bar
  28. 28CSS Search Bar with Dual-Tone Border Outline
  29. 29CSS Glitch Search Bar with RGB Split Effect
  30. 30Mobile-First Compact CSS Search Bar
  31. 31CSS Search Bar with Focus Ring Bloom Animation
  32. 32CSS Search Bar Combo with Scope Selector
  33. 33CSS Search Bar with Inset Pressed 3D Effect
  34. 34CSS Search Bar with Animated Border Trace
  35. 35Floating Card CSS Search Bar (Modal Style)
  36. 36Aurora Gradient CSS Search Bar
Pure CSSMIT licensed

Neon Glow CSS Search Bar (Cyberpunk)

Cyan-and-magenta neon on near-black: the field's glow is a five-layer box-shadow — two tight inner rings for the tube, three wide outer washes for the bloom — and focus runs a slow hue-shifting pulse. Monospace type, scanline grid, zero JavaScript.

Live Demo
Try it

Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149

Nucleo · Affiliate link

Get the Nucleo bundle

The code

<div class="sb-09">
  <button class="sb-09__theme" type="button" aria-pressed="false" aria-label="Switch to dark theme">
    <svg class="sb-09__moon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M20 14.2A8.2 8.2 0 0 1 9.8 4 8.4 8.4 0 1 0 20 14.2"/></svg>
    <svg class="sb-09__sun" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 3.4v2M12 18.6v2M3.4 12h2M18.6 12h2M6 6l1.4 1.4M16.6 16.6 18 18M18 6l-1.4 1.4M7.4 16.6 6 18"/></svg>
  </button>
  <div class="sb-09__stage">
    <div class="sb-09__bar" role="search">
      <svg class="sb-09__ico" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.4" stroke="currentColor" stroke-width="1.7"/><path d="m16 16 4.4 4.4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
      <label class="sb-09__vh" for="sb-09-input">Search the grid</label>
      <input class="sb-09__input" id="sb-09-input" type="search" placeholder="search://the-grid" autocomplete="off" spellcheck="false">
      <span class="sb-09__status" aria-hidden="true">ONLINE</span>
    </div>
  </div>
</div>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap');

@property --sb-09-neon {
  syntax: '<color>';
  inherits: true;
  initial-value: #22d3ee;
}

@property --sb-09-neon2 {
  syntax: '<color>';
  inherits: true;
  initial-value: #f472b6;
}

.sb-09 {
  --bg: #05060a;
  --ink: #e8fbff;
  --muted: #6fd8e8;
  --neon: #22d3ee;
  --neon2: #f472b6;
  --ring: #22d3ee;
  --sb-09-neon: #22d3ee;
  --sb-09-neon2: #f472b6;
  position: relative;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  overflow: hidden;
  box-sizing: border-box;
  color: var(--ink);
  font-family: "JetBrains Mono",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  background: radial-gradient(38rem 24rem at 50% 46%, rgba(34,211,238,.10), transparent 70%), radial-gradient(30rem 20rem at 78% 82%, rgba(244,114,182,.10), transparent 70%), var(--bg);
  -webkit-font-smoothing: antialiased;
}

.sb-09 *,
.sb-09 *::before,
.sb-09 *::after {
  box-sizing: border-box;
}

.sb-09::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .5;
  background: repeating-linear-gradient(0deg, rgba(255,255,255,.035) 0 1px, transparent 1px 3px);
}

.sb-09__stage {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(1rem,4vw,3rem);
}

.sb-09__vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.sb-09__bar {
  display: flex;
  align-items: center;
  gap: .85rem;
  inline-size: min(32rem,100%);
  min-block-size: 56px;
  padding-inline: 1.1rem;
  border: 0;
  border-radius: 12px;
  background: rgba(8,12,20,.9);
  box-shadow: inset 0 0 0 1px var(--sb-09-neon), inset 0 0 14px -6px var(--sb-09-neon), 0 0 8px -2px var(--sb-09-neon), 0 0 26px -8px var(--sb-09-neon2), 0 0 56px -14px var(--sb-09-neon2);
  transition: box-shadow .3s ease, translate .3s ease;
}

.sb-09__bar:focus-within {
  translate: 0 -1px;
  animation: sb-09-pulse 3.2s ease-in-out infinite;
}

@keyframes sb-09-pulse {
  0%,
    100% {
    --sb-09-neon: #22d3ee;
    --sb-09-neon2: #f472b6;
    box-shadow: inset 0 0 0 1px var(--sb-09-neon), inset 0 0 16px -6px var(--sb-09-neon), 0 0 10px -2px var(--sb-09-neon), 0 0 34px -8px var(--sb-09-neon2), 0 0 72px -14px var(--sb-09-neon2);
  }

  50% {
    --sb-09-neon: #a78bfa;
    --sb-09-neon2: #22d3ee;
    box-shadow: inset 0 0 0 1px var(--sb-09-neon), inset 0 0 22px -6px var(--sb-09-neon), 0 0 14px -2px var(--sb-09-neon), 0 0 46px -8px var(--sb-09-neon2), 0 0 92px -14px var(--sb-09-neon2);
  }
}

.sb-09__ico {
  inline-size: 20px;
  block-size: 20px;
  flex: none;
  color: var(--neon);
  filter: drop-shadow(0 0 6px var(--neon));
}

.sb-09__input {
  flex: 1;
  min-inline-size: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: 500 .98rem/1 inherit;
  letter-spacing: .01em;
  caret-color: var(--neon2);
  text-shadow: 0 0 12px rgba(34,211,238,.45);
}

.sb-09__input::placeholder {
  color: var(--muted);
  opacity: .75;
  text-shadow: 0 0 10px rgba(34,211,238,.35);
}

.sb-09__input:focus {
  outline: none;
}

.sb-09__input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

.sb-09__status {
  flex: none;
  padding: .28rem .5rem;
  border-radius: 6px;
  color: var(--neon2);
  font: 700 .64rem/1 inherit;
  letter-spacing: .16em;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--neon2) 55%, transparent), 0 0 12px -4px var(--neon2);
}

.sb-09 :focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 4px;
}

.sb-09__input:focus-visible {
  outline: none;
}

.sb-09[data-theme="light"] {
  --bg: #f4f6fb;
  --ink: #0b1120;
  --muted: #5b6478;
  --neon: #0891b2;
  --neon2: #be185d;
  --ring: #0891b2;
  --sb-09-neon: #0891b2;
  --sb-09-neon2: #be185d;
  background: radial-gradient(38rem 24rem at 50% 46%, rgba(8,145,178,.10), transparent 70%), var(--bg);
}

.sb-09[data-theme="light"]::before {
  opacity: 0;
}

.sb-09[data-theme="light"] .sb-09__bar {
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--sb-09-neon), 0 0 0 4px rgba(8,145,178,.12), 0 18px 36px -22px rgba(8,17,32,.5);
  animation: none;
}

.sb-09[data-theme="light"] .sb-09__input,
.sb-09[data-theme="light"] .sb-09__input::placeholder {
  text-shadow: none;
}

@media (prefers-color-scheme: light) {
  .sb-09:not([data-theme="dark"]) {
    --bg: #f4f6fb;
    --ink: #0b1120;
    --muted: #5b6478;
    --neon: #0891b2;
    --neon2: #be185d;
    --ring: #0891b2;
    --sb-09-neon: #0891b2;
    --sb-09-neon2: #be185d;
    background: radial-gradient(38rem 24rem at 50% 46%, rgba(8,145,178,.10), transparent 70%), var(--bg);
  }

  .sb-09:not([data-theme="dark"])::before {
    opacity: 0;
  }

  .sb-09:not([data-theme="dark"]) .sb-09__bar {
    background: #fff;
    box-shadow: inset 0 0 0 1px var(--sb-09-neon), 0 0 0 4px rgba(8,145,178,.12), 0 18px 36px -22px rgba(8,17,32,.5);
    animation: none;
  }

  .sb-09:not([data-theme="dark"]) .sb-09__input,
    .sb-09:not([data-theme="dark"]) .sb-09__input::placeholder {
    text-shadow: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sb-09 *,
    .sb-09 *::before,
    .sb-09 *::after {
    animation: none !important;
    transition: none !important;
  }
}

@media (forced-colors: active) {
  .sb-09__bar {
    border: 1px solid CanvasText;
    box-shadow: none;
  }

  .sb-09::before {
    display: none;
  }
}

.sb-09__theme {
  position: absolute;
  inset-block-start: clamp(.75rem,2vw,1.25rem);
  inset-inline-end: clamp(.75rem,2vw,1.25rem);
  z-index: 50;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
  border-radius: 999px;
  border: 1px solid rgba(0,0,0,.12);
  color: currentColor;
  background: rgba(255,255,255,.72);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: background .25s ease, transform .25s cubic-bezier(.16,1,.3,1), border-color .25s ease;
}

.sb-09[data-theme="dark"] .sb-09__theme {
  background: rgba(20,20,28,.72);
  border-color: rgba(255,255,255,.15);
  color: #fff;
}

@media (prefers-color-scheme: dark) {
  .sb-09:not([data-theme="light"]) .sb-09__theme {
    background: rgba(20,20,28,.72);
    border-color: rgba(255,255,255,.15);
    color: #fff;
  }
}

.sb-09__theme:hover {
  transform: translateY(-1px);
  border-color: rgba(0,0,0,.24);
}

.sb-09[data-theme="dark"] .sb-09__theme:hover,
.sb-09:not([data-theme="light"]) .sb-09__theme:hover {
  border-color: rgba(255,255,255,.3);
}

.sb-09__theme:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

.sb-09__theme svg {
  grid-area: 1/1;
  inline-size: 1.1rem;
  block-size: 1.1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.sb-09__sun {
  display: none;
}

.sb-09__theme[aria-pressed="true"] .sb-09__sun {
  display: block;
}

.sb-09__theme[aria-pressed="true"] .sb-09__moon {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .sb-09__theme {
    transition: none;
  }

  .sb-09__theme:hover {
    transform: none;
  }
}
(()=>{const r=document.querySelector('.sb-09');if(!r)return;const t=r.querySelector('.sb-09__theme');if(!t)return;const dark=()=>(r.dataset.theme||(matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'))==='dark';const sync=()=>{t.setAttribute('aria-pressed',String(dark()));t.setAttribute('aria-label',dark()?'Switch to light theme':'Switch to dark theme');};t.addEventListener('click',()=>{r.dataset.theme=dark()?'light':'dark';sync();});matchMedia('(prefers-color-scheme: dark)').addEventListener('change',()=>{if(!r.dataset.theme)sync();});sync();})();
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 Search Bar 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: Neon Glow CSS Search Bar (Cyberpunk)
Source: https://codefronts.com/components/css-search-boxes/neon-outline/

Cyan-and-magenta neon on near-black: the field's glow is a five-layer box-shadow — two tight inner rings for the tube, three wide outer washes for the bloom — and focus runs a slow hue-shifting pulse. Monospace type, scanline grid, zero JavaScript.
## HTML
```html
<div class="sb-09">
  <button class="sb-09__theme" type="button" aria-pressed="false" aria-label="Switch to dark theme">
    <svg class="sb-09__moon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M20 14.2A8.2 8.2 0 0 1 9.8 4 8.4 8.4 0 1 0 20 14.2"/></svg>
    <svg class="sb-09__sun" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 3.4v2M12 18.6v2M3.4 12h2M18.6 12h2M6 6l1.4 1.4M16.6 16.6 18 18M18 6l-1.4 1.4M7.4 16.6 6 18"/></svg>
  </button>
  <div class="sb-09__stage">
    <div class="sb-09__bar" role="search">
      <svg class="sb-09__ico" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.4" stroke="currentColor" stroke-width="1.7"/><path d="m16 16 4.4 4.4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
      <label class="sb-09__vh" for="sb-09-input">Search the grid</label>
      <input class="sb-09__input" id="sb-09-input" type="search" placeholder="search://the-grid" autocomplete="off" spellcheck="false">
      <span class="sb-09__status" aria-hidden="true">ONLINE</span>
    </div>
  </div>
</div>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap');

@property --sb-09-neon {
  syntax: '<color>';
  inherits: true;
  initial-value: #22d3ee;
}

@property --sb-09-neon2 {
  syntax: '<color>';
  inherits: true;
  initial-value: #f472b6;
}

.sb-09 {
  --bg: #05060a;
  --ink: #e8fbff;
  --muted: #6fd8e8;
  --neon: #22d3ee;
  --neon2: #f472b6;
  --ring: #22d3ee;
  --sb-09-neon: #22d3ee;
  --sb-09-neon2: #f472b6;
  position: relative;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  overflow: hidden;
  box-sizing: border-box;
  color: var(--ink);
  font-family: "JetBrains Mono",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  background: radial-gradient(38rem 24rem at 50% 46%, rgba(34,211,238,.10), transparent 70%), radial-gradient(30rem 20rem at 78% 82%, rgba(244,114,182,.10), transparent 70%), var(--bg);
  -webkit-font-smoothing: antialiased;
}

.sb-09 *,
.sb-09 *::before,
.sb-09 *::after {
  box-sizing: border-box;
}

.sb-09::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .5;
  background: repeating-linear-gradient(0deg, rgba(255,255,255,.035) 0 1px, transparent 1px 3px);
}

.sb-09__stage {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(1rem,4vw,3rem);
}

.sb-09__vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.sb-09__bar {
  display: flex;
  align-items: center;
  gap: .85rem;
  inline-size: min(32rem,100%);
  min-block-size: 56px;
  padding-inline: 1.1rem;
  border: 0;
  border-radius: 12px;
  background: rgba(8,12,20,.9);
  box-shadow: inset 0 0 0 1px var(--sb-09-neon), inset 0 0 14px -6px var(--sb-09-neon), 0 0 8px -2px var(--sb-09-neon), 0 0 26px -8px var(--sb-09-neon2), 0 0 56px -14px var(--sb-09-neon2);
  transition: box-shadow .3s ease, translate .3s ease;
}

.sb-09__bar:focus-within {
  translate: 0 -1px;
  animation: sb-09-pulse 3.2s ease-in-out infinite;
}

@keyframes sb-09-pulse {
  0%,
    100% {
    --sb-09-neon: #22d3ee;
    --sb-09-neon2: #f472b6;
    box-shadow: inset 0 0 0 1px var(--sb-09-neon), inset 0 0 16px -6px var(--sb-09-neon), 0 0 10px -2px var(--sb-09-neon), 0 0 34px -8px var(--sb-09-neon2), 0 0 72px -14px var(--sb-09-neon2);
  }

  50% {
    --sb-09-neon: #a78bfa;
    --sb-09-neon2: #22d3ee;
    box-shadow: inset 0 0 0 1px var(--sb-09-neon), inset 0 0 22px -6px var(--sb-09-neon), 0 0 14px -2px var(--sb-09-neon), 0 0 46px -8px var(--sb-09-neon2), 0 0 92px -14px var(--sb-09-neon2);
  }
}

.sb-09__ico {
  inline-size: 20px;
  block-size: 20px;
  flex: none;
  color: var(--neon);
  filter: drop-shadow(0 0 6px var(--neon));
}

.sb-09__input {
  flex: 1;
  min-inline-size: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: 500 .98rem/1 inherit;
  letter-spacing: .01em;
  caret-color: var(--neon2);
  text-shadow: 0 0 12px rgba(34,211,238,.45);
}

.sb-09__input::placeholder {
  color: var(--muted);
  opacity: .75;
  text-shadow: 0 0 10px rgba(34,211,238,.35);
}

.sb-09__input:focus {
  outline: none;
}

.sb-09__input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

.sb-09__status {
  flex: none;
  padding: .28rem .5rem;
  border-radius: 6px;
  color: var(--neon2);
  font: 700 .64rem/1 inherit;
  letter-spacing: .16em;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--neon2) 55%, transparent), 0 0 12px -4px var(--neon2);
}

.sb-09 :focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 4px;
}

.sb-09__input:focus-visible {
  outline: none;
}

.sb-09[data-theme="light"] {
  --bg: #f4f6fb;
  --ink: #0b1120;
  --muted: #5b6478;
  --neon: #0891b2;
  --neon2: #be185d;
  --ring: #0891b2;
  --sb-09-neon: #0891b2;
  --sb-09-neon2: #be185d;
  background: radial-gradient(38rem 24rem at 50% 46%, rgba(8,145,178,.10), transparent 70%), var(--bg);
}

.sb-09[data-theme="light"]::before {
  opacity: 0;
}

.sb-09[data-theme="light"] .sb-09__bar {
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--sb-09-neon), 0 0 0 4px rgba(8,145,178,.12), 0 18px 36px -22px rgba(8,17,32,.5);
  animation: none;
}

.sb-09[data-theme="light"] .sb-09__input,
.sb-09[data-theme="light"] .sb-09__input::placeholder {
  text-shadow: none;
}

@media (prefers-color-scheme: light) {
  .sb-09:not([data-theme="dark"]) {
    --bg: #f4f6fb;
    --ink: #0b1120;
    --muted: #5b6478;
    --neon: #0891b2;
    --neon2: #be185d;
    --ring: #0891b2;
    --sb-09-neon: #0891b2;
    --sb-09-neon2: #be185d;
    background: radial-gradient(38rem 24rem at 50% 46%, rgba(8,145,178,.10), transparent 70%), var(--bg);
  }

  .sb-09:not([data-theme="dark"])::before {
    opacity: 0;
  }

  .sb-09:not([data-theme="dark"]) .sb-09__bar {
    background: #fff;
    box-shadow: inset 0 0 0 1px var(--sb-09-neon), 0 0 0 4px rgba(8,145,178,.12), 0 18px 36px -22px rgba(8,17,32,.5);
    animation: none;
  }

  .sb-09:not([data-theme="dark"]) .sb-09__input,
    .sb-09:not([data-theme="dark"]) .sb-09__input::placeholder {
    text-shadow: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sb-09 *,
    .sb-09 *::before,
    .sb-09 *::after {
    animation: none !important;
    transition: none !important;
  }
}

@media (forced-colors: active) {
  .sb-09__bar {
    border: 1px solid CanvasText;
    box-shadow: none;
  }

  .sb-09::before {
    display: none;
  }
}

.sb-09__theme {
  position: absolute;
  inset-block-start: clamp(.75rem,2vw,1.25rem);
  inset-inline-end: clamp(.75rem,2vw,1.25rem);
  z-index: 50;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
  border-radius: 999px;
  border: 1px solid rgba(0,0,0,.12);
  color: currentColor;
  background: rgba(255,255,255,.72);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: background .25s ease, transform .25s cubic-bezier(.16,1,.3,1), border-color .25s ease;
}

.sb-09[data-theme="dark"] .sb-09__theme {
  background: rgba(20,20,28,.72);
  border-color: rgba(255,255,255,.15);
  color: #fff;
}

@media (prefers-color-scheme: dark) {
  .sb-09:not([data-theme="light"]) .sb-09__theme {
    background: rgba(20,20,28,.72);
    border-color: rgba(255,255,255,.15);
    color: #fff;
  }
}

.sb-09__theme:hover {
  transform: translateY(-1px);
  border-color: rgba(0,0,0,.24);
}

.sb-09[data-theme="dark"] .sb-09__theme:hover,
.sb-09:not([data-theme="light"]) .sb-09__theme:hover {
  border-color: rgba(255,255,255,.3);
}

.sb-09__theme:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

.sb-09__theme svg {
  grid-area: 1/1;
  inline-size: 1.1rem;
  block-size: 1.1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.sb-09__sun {
  display: none;
}

.sb-09__theme[aria-pressed="true"] .sb-09__sun {
  display: block;
}

.sb-09__theme[aria-pressed="true"] .sb-09__moon {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .sb-09__theme {
    transition: none;
  }

  .sb-09__theme:hover {
    transform: none;
  }
}
```

## JavaScript
```js
(()=>{const r=document.querySelector('.sb-09');if(!r)return;const t=r.querySelector('.sb-09__theme');if(!t)return;const dark=()=>(r.dataset.theme||(matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'))==='dark';const sync=()=>{t.setAttribute('aria-pressed',String(dark()));t.setAttribute('aria-label',dark()?'Switch to light theme':'Switch to dark theme');};t.addEventListener('click',()=>{r.dataset.theme=dark()?'light':'dark';sync();});matchMedia('(prefers-color-scheme: dark)').addEventListener('change',()=>{if(!r.dataset.theme)sync();});sync();})();
```

How this works

Real neon has two light sources — the tube itself (tight, bright, almost white at the core) and the bloom it throws onto the surrounding surface (wide, dim, saturated). One box-shadow cannot do both, so stack them:

.sb-09__bar{
  box-shadow:
    inset 0 0 0 1px var(--neon),          /* the tube wall */
    inset 0 0 12px -4px var(--neon),      /* inner bleed */
    0 0 8px -2px var(--neon),             /* close bloom */
    0 0 28px -6px var(--neon2),           /* mid bloom, second hue */
    0 0 60px -12px var(--neon2);          /* far wash */
}

Animating the hue. Custom properties are strings by default and cannot interpolate. Registering them tells the engine their type, so a keyframe can cross-fade the colour instead of snapping:

@property --sb-09-neon{syntax:'<color>'; inherits:true; initial-value:#22d3ee;}
@keyframes sb-09-pulse{50%{--sb-09-neon:#f0f; box-shadow:/* wider bloom */;}}

The pulse only runs on :focus-within, at 3.2s — slow enough to read as ambient light rather than a strobe, and disabled outright under prefers-reduced-motion.

Make it yours

  • Change the two hues in --neon (cyan) and --neon2 (magenta). Keep them ~120° apart for the classic cyberpunk split; 30° apart gives a single-colour tube.
  • Reduce the bloom on lighter backgrounds by removing the last shadow layer — bloom over a light surface reads as blur, not light.
  • Speed up the pulse to 1.6s for an alert state, or freeze it and toggle a brighter --neon instead.
  • Swap the mono face for your own; the demo uses JetBrains Mono with a full ui-monospace fallback stack so the layout is identical if the web font never loads.

Gotchas — read before shipping

  • Neon needs a dark backdrop to be neon. On white, the wide shadow layers read as a grey smudge — this demo is dark-first and its light override deliberately reduces to two layers.
  • Glow + low-contrast text is an accessibility trap. The input text is near-white at 90%+ contrast against the field, and the glow never carries meaning on its own.
  • Large blurred shadows are fill-rate expensive. Keep the total blur radius under ~100px and never animate box-shadow on scroll.
  • @property in a stylesheet must be declared at the top level, not inside a media query or @supports block.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

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

@property is Chrome 85 / Safari 16.4 / Firefox 128; without it the colour tokens still resolve, the pulse just steps between keyframes instead of blending. box-shadow, text-shadow and drop-shadow() are universal.

Techniques used in this demo

Search CodeFronts

Loading…