Neon Border Pulse
Green neon outline whose glow breathes every two seconds, then races and turns white when you hover, tab to or tap the box.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →
3 usage examples



How it works
The .nbp-box (200 × 120 px, 12 px radius) has a solid 2 px #00ff88 border. All the shine comes from box-shadow: several blurred outer glows stacked with one inner glow (inset), with no pseudo-element and no JavaScript.
At rest, the nbpPulse animation (2 s, eased back and forth, looping) takes the glow from a single 5 px halo to three layers of 15, 30 and 60 px, while the border shifts to an aqua #00ffcc. On hover the animation is swapped for nbpPulseIntense, twice as fast: the border turns white at the top of each beat and the glow spreads out to 120 px.
The label is a real link, .nbp-link, whose ::after pseudo-element covers the whole box, so a click anywhere follows it. The box reacts to :hover and :focus-within, which means it also lights up when that link (or any link, button or field you put inside) gets focus. With nothing interactive inside, the box is just a decoration breathing on its own.
The hue is written as three numbers (--nbp-rgb: 0, 255, 136) because the glows reuse it at several opacities through rgba(): changing that single variable recolours the border and every halo.
Accessibility
- Keyboard: Tab reaches the link in the box; the intense pulse starts and a white ring (
--nbp-ring) surrounds the box, a few pixels outside the border, when focus comes from the keyboard. In Safari, Tab only stops on links when the browser's keyboard option is on (Option+Tab otherwise): a Safari setting, not the effect. - Touch: a finger on the link starts the intense pulse in Chromium, Firefox and WebKit (measured with a simulated touch screen, including WebKit, where a plain box with no link does not react).
- Reduced motion: with
prefers-reduced-motion: reducethere is no breathing at all; the border keeps a steady 10 and 30 px glow, and hover or focus turns it white with a wider halo, without flashing. - Decoration only: the glow carries no information. If it signals a state (recording, playable square), write that state as text inside the box, like “REC” in the studio example.
- Flashing: the intense version beats once per second, far from the WCAG limit of three flashes per second; if you shorten
--nbp-speed-hover, stay above 0.4 s.
Browser compatibility
Pure CSS, no JavaScript. Measured in Chromium 151, Firefox 153 and Playwright's WebKit 26.5: 0 errors, two independent copies on one page, hover, Tab, touch, 390 px and reduced motion (no infinite animation left). Minimum versions from @mdn/browser-compat-data: the inset property of the stretched link sets the floor (Chrome 87, Firefox 66, Safari 14.1).
Before :focus-visible (Chrome 86, Firefox 85, Safari 15.4), the white ring does not appear, but the intense pulse still starts on focus. Without inset, write top:0; right:0; bottom:0; left:0 on .nbp-link::after.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0767-root">
<div class="nbp-box">
<a class="nbp-link" href="#neon-pulse">Neon Pulse</a>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
--nbp-rgb |
0, 255, 136 |
Neon colour as three R, G, B numbers: border and glows change together. |
--nbp-peak and --nbp-hot |
#0fc and #fff |
Border colour at the top of a breath, then at the top of an intense beat. |
--nbp-speed |
2s |
Length of one breath at rest. |
--nbp-speed-hover |
1s |
Length of one beat on hover, focus and tap. |
--nbp-w, --nbp-h, --nbp-radius |
200px, 120px, 12px |
Size and corner radius of the box; its width never exceeds the container. |
--nbp-fill |
#0a0a0f |
Box background. Neon stands out on dark; on a light background the green halos almost vanish. |
--nbp-ring |
#fff |
Colour of the keyboard focus ring. |
FAQ
.nbp-link link and give it your URL; put the rest of the content (heading, text) in the box next to it. Its ::after covers the whole box, so the entire frame is clickable, and keyboard focus on that link starts the pulse. For a purely decorative frame, remove the link: the breathing goes on, without a hand cursor.box-shadow makes the browser repaint the halo on every frame. For one or a few frames it does not matter; for a grid of dozens of boxes pulsing at once, keep the neon for the elements that count, like the three playable squares in the example.--nbp-rgb (for instance 255, 64, 96 for red, 56, 189, 248 for sky blue) and set --nbp-peak to a lighter version of the same hue. The white of --nbp-hot goes with every colour.