32 CSS Tab Designs02 / 32

Pure CSSMIT licensed

Neon Electric

Each tab owns its own electric accent via a CSS custom property. The active tab lights up with a neon border and a soft outer glow in its color. Pure CSS via radio inputs and `:has()` panel switching.

Published

Live Demo
Try it

The code

<div class="tt22">
  <nav class="tt22n">
    <input type="radio" name="tt22" id="tt22-r1" checked />
    <label class="tt22b" for="tt22-r1" style="--c: #ff3df5">Pulse</label>
    <input type="radio" name="tt22" id="tt22-r2" />
    <label class="tt22b" for="tt22-r2" style="--c: #3df5ff">Wave</label>
    <input type="radio" name="tt22" id="tt22-r3" />
    <label class="tt22b" for="tt22-r3" style="--c: #caff3d">Surge</label>
    <input type="radio" name="tt22" id="tt22-r4" />
    <label class="tt22b" for="tt22-r4" style="--c: #ff913d">Bloom</label>
  </nav>
  <div class="tt22p">Pulse — short, rhythmic bursts of light.</div>
  <div class="tt22p">Wave — continuous oscillating motion.</div>
  <div class="tt22p">Surge — sudden upward power swell.</div>
  <div class="tt22p">Bloom — soft expanding glow front.</div>
</div>
.tt22 {
  background: #0c0c12;
  padding: 22px 18px;
  font-family: ui-monospace, monospace;
  min-height: 100vh;
  box-sizing: border-box;
  width: 100%;
}

.tt22n {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  min-width: 0;
}

.tt22n input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.tt22b {
  flex: 1;
  min-width: 0;
  padding: 11px 12px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 6px;
  background: transparent;
  font: 700 11px/1 ui-monospace, monospace;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  cursor: pointer;
  text-align: center;
  transition: color 0.25s, border-color 0.25s, box-shadow 0.3s, background 0.25s;
  white-space: nowrap;
}

.tt22b:hover {
  color: rgba(255, 255, 255, 0.85);
  border-color: rgba(255, 255, 255, 0.2);
}

.tt22n input:checked + .tt22b {
  color: var(--c);
  border-color: var(--c);
  background: color-mix(in srgb, var(--c) 12%, transparent);
  box-shadow: 0 0 12px color-mix(in srgb, var(--c) 50%, transparent), inset 0 0 8px color-mix(in srgb, var(--c) 25%, transparent);
}

.tt22n input:focus-visible + .tt22b {
  outline: 2px dashed var(--c);
  outline-offset: 2px;
}

.tt22p {
  display: none;
  padding-top: 18px;
  font: 12px/1.55 ui-monospace, monospace;
  color: rgba(255, 255, 255, 0.6);
  letter-spacing: 0.04em;
}

.tt22:has(#tt22-r1:checked) .tt22p:nth-of-type(1),
.tt22:has(#tt22-r2:checked) .tt22p:nth-of-type(2),
.tt22:has(#tt22-r3:checked) .tt22p:nth-of-type(3),
.tt22:has(#tt22-r4:checked) .tt22p:nth-of-type(4) {
  display: block;
}
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 Tab Design 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 Electric
Source: https://codefronts.com/navigation/css-tabs/neon-electric/

Each tab owns its own electric accent via a CSS custom property. The active tab lights up with a neon border and a soft outer glow in its color. Pure CSS via radio inputs and `:has()` panel switching.
## HTML
```html
<div class="tt22">
  <nav class="tt22n">
    <input type="radio" name="tt22" id="tt22-r1" checked />
    <label class="tt22b" for="tt22-r1" style="--c: #ff3df5">Pulse</label>
    <input type="radio" name="tt22" id="tt22-r2" />
    <label class="tt22b" for="tt22-r2" style="--c: #3df5ff">Wave</label>
    <input type="radio" name="tt22" id="tt22-r3" />
    <label class="tt22b" for="tt22-r3" style="--c: #caff3d">Surge</label>
    <input type="radio" name="tt22" id="tt22-r4" />
    <label class="tt22b" for="tt22-r4" style="--c: #ff913d">Bloom</label>
  </nav>
  <div class="tt22p">Pulse — short, rhythmic bursts of light.</div>
  <div class="tt22p">Wave — continuous oscillating motion.</div>
  <div class="tt22p">Surge — sudden upward power swell.</div>
  <div class="tt22p">Bloom — soft expanding glow front.</div>
</div>
```
## CSS
```css
.tt22 {
  background: #0c0c12;
  padding: 22px 18px;
  font-family: ui-monospace, monospace;
  min-height: 100vh;
  box-sizing: border-box;
  width: 100%;
}

.tt22n {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  min-width: 0;
}

.tt22n input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.tt22b {
  flex: 1;
  min-width: 0;
  padding: 11px 12px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 6px;
  background: transparent;
  font: 700 11px/1 ui-monospace, monospace;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  cursor: pointer;
  text-align: center;
  transition: color 0.25s, border-color 0.25s, box-shadow 0.3s, background 0.25s;
  white-space: nowrap;
}

.tt22b:hover {
  color: rgba(255, 255, 255, 0.85);
  border-color: rgba(255, 255, 255, 0.2);
}

.tt22n input:checked + .tt22b {
  color: var(--c);
  border-color: var(--c);
  background: color-mix(in srgb, var(--c) 12%, transparent);
  box-shadow: 0 0 12px color-mix(in srgb, var(--c) 50%, transparent), inset 0 0 8px color-mix(in srgb, var(--c) 25%, transparent);
}

.tt22n input:focus-visible + .tt22b {
  outline: 2px dashed var(--c);
  outline-offset: 2px;
}

.tt22p {
  display: none;
  padding-top: 18px;
  font: 12px/1.55 ui-monospace, monospace;
  color: rgba(255, 255, 255, 0.6);
  letter-spacing: 0.04em;
}

.tt22:has(#tt22-r1:checked) .tt22p:nth-of-type(1),
.tt22:has(#tt22-r2:checked) .tt22p:nth-of-type(2),
.tt22:has(#tt22-r3:checked) .tt22p:nth-of-type(3),
.tt22:has(#tt22-r4:checked) .tt22p:nth-of-type(4) {
  display: block;
}
```

How this works

The .tt22 shell paints a near-black #0c0c12 register and lays out .tt22n as a flex row with gap: 10px and flex-wrap: wrap so a four-tab strip reflows cleanly on narrow viewports. Each tab is a real radio input plus a .tt22b label pair; the inputs are visually removed with position: absolute; opacity: 0 but stay in the tab order for keyboard drivers. The active accent comes from a per-label --c custom property — #ff3df5, #3df5ff, #caff3d, #ff913d — piped through color-mix(in srgb, var(--c) 12%, transparent) for the tinted background and matching box-shadow for the halo.

Palette is deliberately electric: a chromatic quartet against dark chrome that borrows from Substack Notes and Discord's dark register. Resting labels sit at rgba(255, 255, 255, 0.45), hover lifts to 0.85, and the checked state swaps to var(--c) so the label itself becomes the signal. Typography is a copy-paste ui-monospace, monospace stack at 700 11px/1 with letter-spacing: 0.16em and text-transform: uppercase, which reads as terminal chrome rather than product marketing.

The pattern is pure CSS via :checked + label and :has() panel switching, so there is no hydration cost and INP stays under 200ms — the entire state change is a paint on the tab that received the click. @media (prefers-reduced-motion: reduce) is worth adding since the box-shadow 0.3s transition is visible on the halo. Focus uses outline: 2px dashed var(--c) with outline-offset: 2px, so keyboard drivers see a colored ring that matches the accent for WCAG 2.4.7. Radios auto-form an ARIA radiogroup; for a real tabs pattern, wrap the panel region and add role="tabpanel".

Make it yours

  • Recolor the accents by editing the four inline --c values. Any hue works — brand teal #14b8a6, safety orange #f97316, hot pink #ec4899 — because the halo, border, and tint all read from the single custom property.
  • Swap the mono stack for a display face: font: 700 12px/1 JetBrains Mono, ui-monospace keeps the terminal register, or drop letter-spacing to 0.08em for a softer editorial feel.
  • Adjust the pill shape: raise .tt22b border-radius from 6px to 999px for a full capsule, or drop to 0 for a hard chromatic-bar register with the same electric glow.
  • Light-mode variant: flip .tt22 background to #f8f8fb, resting labels to rgba(15, 15, 30, 0.5), and reduce the checked box-shadow intensity from 50% to 30% in the color-mix so the halo does not blow out on paper.
  • Tailwind arbitrary values: bg-[#0c0c12] on the shell, checked border via color-mix arbitrary values, and inline style attribute setting the --c custom property per label — the :checked + selector ports cleanly to a headless UI radio group.

Gotchas — read before shipping

  • Resting labels at rgba(255, 255, 255, 0.45) on #0c0c12 compute below WCAG 1.4.3 for 11px text. Either lift resting opacity to 0.6, keep the aggressive weight and letter-spacing (which materially helps legibility), or bump size to 12px.
  • color-mix() shipped in Chrome 111, Safari 16.4, and Firefox 113. If your analytics still show meaningful Safari 15 traffic, provide a static rgba fallback before the color-mix declaration so those users still see a tinted background instead of transparent.
  • Radio inputs form a native radiogroup, not a tablist. For the ARIA tabs pattern add role="tablist" on the nav, role="tab" and aria-selected per label, role="tabpanel" per panel, and roving tabindex with Left/Right arrow-key handling for WCAG 2.1.1.
  • The halo box-shadow transitions over 0.3s and reads as a flash on vestibular-sensitive users. Add a @media (prefers-reduced-motion: reduce) block that sets .tt22b transition to none to comply with WCAG 2.3.3.
  • Next.js App Router streams the panel markup before :has() resolves; on Firefox 107 to 120 without :has(), no panel displays. Firefox 121 shipped stable :has(), so gate the panel selector with @supports selector(:has(*)) and provide a JS toggle fallback.
  • The letter-spacing: 0.16em on 11px uppercase text can push a long label past its flex track and clip via white-space: nowrap. Verify with your longest translated string (German plurals are the usual offender) and either shorten copy or drop tracking to 0.1em.

Browser support

ChromeSafariFirefoxEdge
111+16.4+121+111+

color-mix() and :has() panel switching set the floor; earlier browsers still render tabs but lose the tint and panel state.

Techniques used in this demo

Search CodeFronts

Loading…