Pure TailwindMIT licensed

Tailwind Neon Glowing Conic-Border Product Card

A dark card wrapped in a conic-gradient border that ignites and spins on hover, with a blurred copy of itself throwing the glow. The rotation needs a registered @property --angle and a @keyframes — both stylesheet rules — but the animation itself becomes a real utility, because --animate-tpc09-spin in @theme mints animate-tpc09-spin.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="tpc-09 w-full min-h-svh grid place-items-center font-tpc09-sans px-5 py-14 bg-[radial-gradient(120%_120%_at_50%_20%,oklch(0.16_0.02_300),oklch(0.09_0.01_300))]" aria-label="Neon glowing border product card demo">
  <article class="group relative isolate w-80 max-w-full p-0.5 rounded-[20px]">
    <span aria-hidden="true" class="absolute inset-0 -z-10 rounded-[20px] opacity-50 bg-[conic-gradient(from_var(--angle),var(--color-tpc09-c1),var(--color-tpc09-c2),var(--color-tpc09-c3),var(--color-tpc09-c1))] animate-tpc09-spin [animation-play-state:paused] transition-opacity duration-400 group-hover:opacity-100 group-hover:[animation-play-state:running] motion-reduce:animate-none"></span>
    <span aria-hidden="true" class="absolute inset-0 -z-10 rounded-[20px] opacity-25 blur-[18px] bg-[conic-gradient(from_var(--angle),var(--color-tpc09-c1),var(--color-tpc09-c2),var(--color-tpc09-c3),var(--color-tpc09-c1))] animate-tpc09-spin [animation-play-state:paused] transition-opacity duration-400 group-hover:opacity-70 group-hover:[animation-play-state:running] motion-reduce:animate-none"></span>
    <div class="rounded-[18px] overflow-hidden bg-tpc09-face">
      <div role="img" aria-label="Product photo: Flux automatic watch" class="aspect-[16/11] bg-linear-[135deg,var(--color-tpc09-ph),var(--color-tpc09-ph2)] bg-[url('https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=800&h=550&fit=crop&q=70')] bg-cover bg-center"></div>
      <div class="px-5.5 pt-5 pb-5.5">
        <p class="font-tpc09-mono text-[11px] tracking-[0.2em] uppercase text-tpc09-c2">Flux</p>
        <h3 class="mt-1.5 text-[18px] font-semibold text-tpc09-ink text-pretty">Flux Automatic Watch</h3>
        <div class="mt-4.5 flex items-center justify-between gap-3">
          <p class="text-[22px] font-extrabold text-tpc09-hi tabular-nums">$460</p>
          <button type="button" class="min-h-11 h-11 px-5.5 rounded-xl border-0 bg-linear-[120deg,var(--color-tpc09-c1),var(--color-tpc09-c2)] text-tpc09-onacc text-sm font-bold cursor-pointer transition-[filter,scale] duration-200 hover:brightness-110 active:scale-97 focus-visible:outline-3 focus-visible:outline-tpc09-c1 focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
        </div>
      </div>
    </div>
  </article>
</section>
@import "tailwindcss";

@theme {
  --color-tpc09-face: #0b0a11;
  --color-tpc09-face: oklch(0.13 0.012 300);
  --color-tpc09-ph: #171522;
  --color-tpc09-ph: oklch(0.19 0.018 300);
  --color-tpc09-ph2: #0f0e18;
  --color-tpc09-ph2: oklch(0.15 0.015 300);
  --color-tpc09-ink: #f1eefb;
  --color-tpc09-ink: oklch(0.95 0.01 300);
  --color-tpc09-hi: #ffffff;
  --color-tpc09-hi: oklch(1 0 0);
  --color-tpc09-onacc: #0a0713;
  --color-tpc09-onacc: oklch(0.13 0.02 300);
  --color-tpc09-c1: #6fd8ee;
  --color-tpc09-c1: oklch(0.82 0.16 200);
  --color-tpc09-c2: #e055b0;
  --color-tpc09-c2: oklch(0.72 0.24 330);
  --color-tpc09-c3: #f2c94c;
  --color-tpc09-c3: oklch(0.85 0.18 90);
  --font-tpc09-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tpc09-mono: 'JetBrains Mono', ui-monospace, monospace;
  /* An @theme --animate-* entry mints a real utility: animate-tpc09-spin. */
  --animate-tpc09-spin: tpc-09-spin 6s linear infinite;
}
/* The registered angle: unregistered, --angle is a string and will not
   interpolate, so the border would jump rather than sweep. */

@property --angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}

@keyframes tpc-09-spin {
  to {
    --angle: 360deg;
  }
}

.tpc-09 {
  width: 100%;
  min-height: 100svh;
}

.tpc-09 ::selection {
  background: var(--color-tpc09-c2);
  color: #fff;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tpc09-face: #0b0a11;
  --color-tpc09-face: oklch(0.13 0.012 300);
  --color-tpc09-ph: #171522;
  --color-tpc09-ph: oklch(0.19 0.018 300);
  --color-tpc09-ph2: #0f0e18;
  --color-tpc09-ph2: oklch(0.15 0.015 300);
  --color-tpc09-ink: #f1eefb;
  --color-tpc09-ink: oklch(0.95 0.01 300);
  --color-tpc09-hi: #ffffff;
  --color-tpc09-hi: oklch(1 0 0);
  --color-tpc09-onacc: #0a0713;
  --color-tpc09-onacc: oklch(0.13 0.02 300);
  --color-tpc09-c1: #6fd8ee;
  --color-tpc09-c1: oklch(0.82 0.16 200);
  --color-tpc09-c2: #e055b0;
  --color-tpc09-c2: oklch(0.72 0.24 330);
  --color-tpc09-c3: #f2c94c;
  --color-tpc09-c3: oklch(0.85 0.18 90);
  --font-tpc09-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tpc09-mono: 'JetBrains Mono', ui-monospace, monospace;
  /* An @theme --animate-* entry mints a real utility: animate-tpc09-spin. */
  --animate-tpc09-spin: tpc-09-spin 6s linear infinite;
}
/* The registered angle: unregistered, --angle is a string and will not
   interpolate, so the border would jump rather than sweep. */

@property --angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}

@keyframes tpc-09-spin {
  to {
    --angle: 360deg;
  }
}

.tpc-09 {
  width: 100%;
  min-height: 100svh;
}

.tpc-09 ::selection {
  background: var(--color-tpc09-c2);
  color: #fff;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • --animate-tpc09-spin in @theme is the headline: the keyframes stay a stylesheet rule, but applying them becomes animate-tpc09-spin, which then composes with motion-reduce:animate-none like any other utility.
  • Both gradient layers became real aria-hidden spans. As pseudo-elements they would need before:/after: variants on a 120-character gradient plus content-[''] — unreadable, and impossible to give different blur values cleanly.
  • [animation-play-state:paused] is arbitrary and always will be; it is a state, not a design value. Pairing it with a group-hover: variant is exactly what the CSS version did with a descendant selector.
  • isolate + -z-10 replaces the original's isolation:isolate + z-index:-1 one-for-one, and both are core utilities.
  • Enhancement over the CSS original: the two glow layers now fade independently (border 50→100%, glow 25→70%), which makes ignition read as a two-stage event rather than a single opacity jump.
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 demo 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: Tailwind Neon Glowing Conic-Border Product Card
Source: https://codefronts.com/components/tailwind-css-product-cards/tailwind-neon-glowing-conic-border-product-card/

A dark card wrapped in a conic-gradient border that ignites and spins on hover, with a blurred copy of itself throwing the glow. The rotation needs a registered @property --angle and a @keyframes — both stylesheet rules — but the animation itself becomes a real utility, because --animate-tpc09-spin in @theme mints animate-tpc09-spin.
## HTML
```html
<section class="tpc-09 w-full min-h-svh grid place-items-center font-tpc09-sans px-5 py-14 bg-[radial-gradient(120%_120%_at_50%_20%,oklch(0.16_0.02_300),oklch(0.09_0.01_300))]" aria-label="Neon glowing border product card demo">
  <article class="group relative isolate w-80 max-w-full p-0.5 rounded-[20px]">
    <span aria-hidden="true" class="absolute inset-0 -z-10 rounded-[20px] opacity-50 bg-[conic-gradient(from_var(--angle),var(--color-tpc09-c1),var(--color-tpc09-c2),var(--color-tpc09-c3),var(--color-tpc09-c1))] animate-tpc09-spin [animation-play-state:paused] transition-opacity duration-400 group-hover:opacity-100 group-hover:[animation-play-state:running] motion-reduce:animate-none"></span>
    <span aria-hidden="true" class="absolute inset-0 -z-10 rounded-[20px] opacity-25 blur-[18px] bg-[conic-gradient(from_var(--angle),var(--color-tpc09-c1),var(--color-tpc09-c2),var(--color-tpc09-c3),var(--color-tpc09-c1))] animate-tpc09-spin [animation-play-state:paused] transition-opacity duration-400 group-hover:opacity-70 group-hover:[animation-play-state:running] motion-reduce:animate-none"></span>
    <div class="rounded-[18px] overflow-hidden bg-tpc09-face">
      <div role="img" aria-label="Product photo: Flux automatic watch" class="aspect-[16/11] bg-linear-[135deg,var(--color-tpc09-ph),var(--color-tpc09-ph2)] bg-[url('https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=800&h=550&fit=crop&q=70')] bg-cover bg-center"></div>
      <div class="px-5.5 pt-5 pb-5.5">
        <p class="font-tpc09-mono text-[11px] tracking-[0.2em] uppercase text-tpc09-c2">Flux</p>
        <h3 class="mt-1.5 text-[18px] font-semibold text-tpc09-ink text-pretty">Flux Automatic Watch</h3>
        <div class="mt-4.5 flex items-center justify-between gap-3">
          <p class="text-[22px] font-extrabold text-tpc09-hi tabular-nums">$460</p>
          <button type="button" class="min-h-11 h-11 px-5.5 rounded-xl border-0 bg-linear-[120deg,var(--color-tpc09-c1),var(--color-tpc09-c2)] text-tpc09-onacc text-sm font-bold cursor-pointer transition-[filter,scale] duration-200 hover:brightness-110 active:scale-97 focus-visible:outline-3 focus-visible:outline-tpc09-c1 focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
        </div>
      </div>
    </div>
  </article>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tpc09-face: #0b0a11;
  --color-tpc09-face: oklch(0.13 0.012 300);
  --color-tpc09-ph: #171522;
  --color-tpc09-ph: oklch(0.19 0.018 300);
  --color-tpc09-ph2: #0f0e18;
  --color-tpc09-ph2: oklch(0.15 0.015 300);
  --color-tpc09-ink: #f1eefb;
  --color-tpc09-ink: oklch(0.95 0.01 300);
  --color-tpc09-hi: #ffffff;
  --color-tpc09-hi: oklch(1 0 0);
  --color-tpc09-onacc: #0a0713;
  --color-tpc09-onacc: oklch(0.13 0.02 300);
  --color-tpc09-c1: #6fd8ee;
  --color-tpc09-c1: oklch(0.82 0.16 200);
  --color-tpc09-c2: #e055b0;
  --color-tpc09-c2: oklch(0.72 0.24 330);
  --color-tpc09-c3: #f2c94c;
  --color-tpc09-c3: oklch(0.85 0.18 90);
  --font-tpc09-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tpc09-mono: 'JetBrains Mono', ui-monospace, monospace;
  /* An @theme --animate-* entry mints a real utility: animate-tpc09-spin. */
  --animate-tpc09-spin: tpc-09-spin 6s linear infinite;
}
/* The registered angle: unregistered, --angle is a string and will not
   interpolate, so the border would jump rather than sweep. */

@property --angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}

@keyframes tpc-09-spin {
  to {
    --angle: 360deg;
  }
}

.tpc-09 {
  width: 100%;
  min-height: 100svh;
}

.tpc-09 ::selection {
  background: var(--color-tpc09-c2);
  color: #fff;
}
```

How this works

The animation is a theme token. This is the neatest v4 win in the collection:

@theme {
  --animate-tpc09-spin: tpc-09-spin 6s linear infinite;
}
@keyframes tpc-09-spin { to { --angle: 360deg } }

The keyframes stay in the stylesheet — they have to, they are a rule — but animate-tpc09-spin is now a utility you can put on any element and pair with variants like motion-reduce:animate-none.

Why @property is mandatory. An unregistered --angle is a string, and strings do not interpolate: the border would jump from 0deg to 360deg with nothing in between. Registering it as <angle> is what makes the sweep smooth, and it is the reason this pattern has a 2022 floor rather than a 2018 one.

Two layers, one gradient. The crisp layer is the border; the same gradient with blur-[18px] is the glow. They share the same --angle, so they rotate in lockstep — which is what makes the glow read as light coming off the border rather than a second effect.

Make it yours

  • Neon hues: --color-tpc09-c1/c2/c3 in @theme. Dual-tone (cyan/magenta) reads cyberpunk; a full spectrum reads launch-day.
  • Speed: the 6s in --animate-tpc09-spin. Under 3s it reads frantic.
  • Border thickness: the card's p-0.5 — that padding IS the border width.
  • Always-on: delete the [animation-play-state:paused] utility and the card is permanently lit.
  • Glow size: blur-[18px] on the second layer, plus its hover opacity.

Gotchas — read before shipping

  • Animating a custom property requires @property with a typed syntax. Without it you get a static gradient, not a broken card — document it as the fallback.
  • The card face must be fully opaque above the gradient layers, or the border colour bleeds through the content.
  • isolate on the card is what makes -z-10 on the layers stay inside it. Without it the glow can slide under the page background.
  • A spinning gradient plus an 18px blur is paint-heavy. One or two feature cards, never a grid.
  • The paused/running trick needs the animation declared at rest — group-hover:animate-tpc09-spin alone would restart the sweep from 0deg on every hover.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

@property-driven gradient animation: Chrome 85+, Safari 16.4+, Firefox 128+. Where @property is missing the border shows a static gradient and the card is otherwise unaffected.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Theme tokensset in @theme, used by a utility

Plain CSSno Tailwind surface

HTML & JSno Tailwind involved

Search CodeFronts

Loading…