07 / 20
All 20 in 20 Tailwind Liquid Glass Effects
- 01Tailwind Liquid Glass Card with Hover Refraction
- 02Tailwind Liquid Glass Button with Glossy Highlight
- 03Tailwind Liquid Glass Navigation Bar
- 04Tailwind Liquid Gooey Toggle Switch
- 05Tailwind Liquid Glass Modal Dialog
- 06Tailwind Liquid Glass Theme Switcher
- 07Tailwind Liquid Glass Input Form Fields
- 08Tailwind SVG Displacement Liquid Glass Background
- 09Tailwind Liquid Glass Dropdown Menu
- 10Tailwind Liquid Glass Pricing Table
- 11Tailwind Liquid Glass Tooltip Popover
- 12Tailwind Liquid Glass Audio Player UI
- 13Tailwind Liquid Glass Range Slider
- 14Tailwind Liquid Glass Toast Notification
- 15Tailwind Liquid Glass Sidebar Navigation
- 16Tailwind Liquid Glass Accordion
- 17Tailwind Liquid Glass Login Card
- 18Tailwind Liquid Glass Floating Action Button
- 19Tailwind Liquid Glass Loading Skeleton
- 20Tailwind Liquid Glass Multi-Step Form Wizard
Tailwind Liquid Glass Input Form Fields
A sign-up form where focusing a field lights a refractive border that travels around it. The port keeps the one thing utilities genuinely cannot do — @property registering the angle as an <angle> so it can tween — in CSS, and expresses everything else, including the mask-composite rim trick, as before: utilities under a focus-within: variant.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="lgt-07 grid w-full min-h-svh place-items-center p-15 font-lgt07-sans [background:conic-gradient(from_210deg_at_30%_30%,#2a2350,#3a2a60,#1c2450,#2a2350)]" aria-label="Tailwind liquid glass form fields">
<form novalidate class="w-[min(400px,92vw)] rounded-[26px] border border-white/28 bg-white/10 p-8.5 backdrop-blur-[22px] backdrop-saturate-170 shadow-[inset_0_1px_0_rgba(255,255,255,.4),0_30px_60px_-30px_rgba(0,0,0,.6)]">
<h3 class="mb-5.5 text-2xl font-extrabold text-white">Create account</h3>
<div class="mb-4.5">
<label for="lgt-07-name" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Full name</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-name" type="text" autocomplete="name" placeholder="Ada Lovelace" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<div class="mb-4.5">
<label for="lgt-07-email" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Email</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-email" type="email" autocomplete="email" placeholder="ada@studio.dev" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<div class="mb-4.5">
<label for="lgt-07-pass" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Password</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-pass" type="password" autocomplete="new-password" placeholder="••••••••" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<button type="submit" class="mt-1.5 w-full cursor-pointer rounded-[14px] border border-lgt07-accent/60 bg-linear-to-b from-lgt07-accent-top to-lgt07-accent py-3.5 text-base font-bold text-white shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_14px_28px_-16px_rgba(0,0,0,.6)] transition-transform duration-150 hover:-translate-y-0.5 focus-visible:-translate-y-0.5 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white motion-reduce:transition-none">Sign up</button>
</form>
</section><section class="lgt-07 grid w-full min-h-svh place-items-center p-15 font-lgt07-sans [background:conic-gradient(from_210deg_at_30%_30%,#2a2350,#3a2a60,#1c2450,#2a2350)]" aria-label="Tailwind liquid glass form fields">
<form novalidate class="w-[min(400px,92vw)] rounded-[26px] border border-white/28 bg-white/10 p-8.5 backdrop-blur-[22px] backdrop-saturate-170 shadow-[inset_0_1px_0_rgba(255,255,255,.4),0_30px_60px_-30px_rgba(0,0,0,.6)]">
<h3 class="mb-5.5 text-2xl font-extrabold text-white">Create account</h3>
<div class="mb-4.5">
<label for="lgt-07-name" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Full name</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-name" type="text" autocomplete="name" placeholder="Ada Lovelace" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<div class="mb-4.5">
<label for="lgt-07-email" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Email</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-email" type="email" autocomplete="email" placeholder="ada@studio.dev" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<div class="mb-4.5">
<label for="lgt-07-pass" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Password</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-pass" type="password" autocomplete="new-password" placeholder="••••••••" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<button type="submit" class="mt-1.5 w-full cursor-pointer rounded-[14px] border border-lgt07-accent/60 bg-linear-to-b from-lgt07-accent-top to-lgt07-accent py-3.5 text-base font-bold text-white shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_14px_28px_-16px_rgba(0,0,0,.6)] transition-transform duration-150 hover:-translate-y-0.5 focus-visible:-translate-y-0.5 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white motion-reduce:transition-none">Sign up</button>
</form>
</section>@import "tailwindcss";
/* Not portable to a utility, and must not be dropped: registering the angle as an
<angle> is what lets the browser interpolate it instead of snapping. */
@property --lgt-07-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-lgt07-accent: #8b5cf6;
--color-lgt07-accent: oklch(0.68 0.19 285);
--color-lgt07-accent-top: #a78bfa;
--color-lgt07-accent-top: oklch(0.74 0.16 285);
--font-lgt07-sans: 'Manrope', system-ui, sans-serif;
--animate-lgt07-spin: lgt-07-spin 3s linear infinite;
}
@keyframes lgt-07-spin {
to {
--lgt-07-angle: 360deg;
}
}@import "tailwindcss";
/* Not portable to a utility, and must not be dropped: registering the angle as an
<angle> is what lets the browser interpolate it instead of snapping. */
@property --lgt-07-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-lgt07-accent: #8b5cf6;
--color-lgt07-accent: oklch(0.68 0.19 285);
--color-lgt07-accent-top: #a78bfa;
--color-lgt07-accent-top: oklch(0.74 0.16 285);
--font-lgt07-sans: 'Manrope', system-ui, sans-serif;
--animate-lgt07-spin: lgt-07-spin 3s linear infinite;
}
@keyframes lgt-07-spin {
to {
--lgt-07-angle: 360deg;
}
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<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.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
/* Not portable to a utility, and must not be dropped: registering the angle as an
<angle> is what lets the browser interpolate it instead of snapping. */
@property --lgt-07-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-lgt07-accent: #8b5cf6;
--color-lgt07-accent: oklch(0.68 0.19 285);
--color-lgt07-accent-top: #a78bfa;
--color-lgt07-accent-top: oklch(0.74 0.16 285);
--font-lgt07-sans: 'Manrope', system-ui, sans-serif;
--animate-lgt07-spin: lgt-07-spin 3s linear infinite;
}
@keyframes lgt-07-spin {
to {
--lgt-07-angle: 360deg;
}
}@import "tailwindcss";
/* Not portable to a utility, and must not be dropped: registering the angle as an
<angle> is what lets the browser interpolate it instead of snapping. */
@property --lgt-07-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-lgt07-accent: #8b5cf6;
--color-lgt07-accent: oklch(0.68 0.19 285);
--color-lgt07-accent-top: #a78bfa;
--color-lgt07-accent-top: oklch(0.74 0.16 285);
--font-lgt07-sans: 'Manrope', system-ui, sans-serif;
--animate-lgt07-spin: lgt-07-spin 3s linear infinite;
}
@keyframes lgt-07-spin {
to {
--lgt-07-angle: 360deg;
}
}<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=Manrope:wght@400;600;800&display=swap">
<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=Manrope:wght@400;600;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
@propertystays in CSS because it is a type registration, not a style — and without it the conic border cannot tween.- The mask-composite rim trick becomes three arbitrary
before:utilities, so the technique is visible on the element that uses it instead of buried in a stylesheet. focus-within:replaces the CSS version's identical selector and remains the entire state machine — no JS focus handlers.- The spin is an
--animate-*theme entry, so retiming every field is a one-line change. placeholder:andfocus:variants absorb what were two separate rules per input.
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 Liquid Glass Input Form Fields
Source: https://codefronts.com/design-styles/tailwind-liquid-glass-effects/tailwind-liquid-glass-input-form-fields/
A sign-up form where focusing a field lights a refractive border that travels around it. The port keeps the one thing utilities genuinely cannot do — @property registering the angle as an <angle> so it can tween — in CSS, and expresses everything else, including the mask-composite rim trick, as before: utilities under a focus-within: variant.
## HTML
```html
<section class="lgt-07 grid w-full min-h-svh place-items-center p-15 font-lgt07-sans [background:conic-gradient(from_210deg_at_30%_30%,#2a2350,#3a2a60,#1c2450,#2a2350)]" aria-label="Tailwind liquid glass form fields">
<form novalidate class="w-[min(400px,92vw)] rounded-[26px] border border-white/28 bg-white/10 p-8.5 backdrop-blur-[22px] backdrop-saturate-170 shadow-[inset_0_1px_0_rgba(255,255,255,.4),0_30px_60px_-30px_rgba(0,0,0,.6)]">
<h3 class="mb-5.5 text-2xl font-extrabold text-white">Create account</h3>
<div class="mb-4.5">
<label for="lgt-07-name" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Full name</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-name" type="text" autocomplete="name" placeholder="Ada Lovelace" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<div class="mb-4.5">
<label for="lgt-07-email" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Email</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-email" type="email" autocomplete="email" placeholder="ada@studio.dev" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<div class="mb-4.5">
<label for="lgt-07-pass" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Password</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-pass" type="password" autocomplete="new-password" placeholder="••••••••" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<button type="submit" class="mt-1.5 w-full cursor-pointer rounded-[14px] border border-lgt07-accent/60 bg-linear-to-b from-lgt07-accent-top to-lgt07-accent py-3.5 text-base font-bold text-white shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_14px_28px_-16px_rgba(0,0,0,.6)] transition-transform duration-150 hover:-translate-y-0.5 focus-visible:-translate-y-0.5 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white motion-reduce:transition-none">Sign up</button>
</form>
</section>
```
## CSS
```css
@import "tailwindcss";
/* Not portable to a utility, and must not be dropped: registering the angle as an
<angle> is what lets the browser interpolate it instead of snapping. */
@property --lgt-07-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-lgt07-accent: #8b5cf6;
--color-lgt07-accent: oklch(0.68 0.19 285);
--color-lgt07-accent-top: #a78bfa;
--color-lgt07-accent-top: oklch(0.74 0.16 285);
--font-lgt07-sans: 'Manrope', system-ui, sans-serif;
--animate-lgt07-spin: lgt-07-spin 3s linear infinite;
}
@keyframes lgt-07-spin {
to {
--lgt-07-angle: 360deg;
}
}
```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 Liquid Glass Input Form Fields
Source: https://codefronts.com/design-styles/tailwind-liquid-glass-effects/tailwind-liquid-glass-input-form-fields/
A sign-up form where focusing a field lights a refractive border that travels around it. The port keeps the one thing utilities genuinely cannot do — @property registering the angle as an <angle> so it can tween — in CSS, and expresses everything else, including the mask-composite rim trick, as before: utilities under a focus-within: variant.
## HTML
```html
<section class="lgt-07 grid w-full min-h-svh place-items-center p-15 font-lgt07-sans [background:conic-gradient(from_210deg_at_30%_30%,#2a2350,#3a2a60,#1c2450,#2a2350)]" aria-label="Tailwind liquid glass form fields">
<form novalidate class="w-[min(400px,92vw)] rounded-[26px] border border-white/28 bg-white/10 p-8.5 backdrop-blur-[22px] backdrop-saturate-170 shadow-[inset_0_1px_0_rgba(255,255,255,.4),0_30px_60px_-30px_rgba(0,0,0,.6)]">
<h3 class="mb-5.5 text-2xl font-extrabold text-white">Create account</h3>
<div class="mb-4.5">
<label for="lgt-07-name" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Full name</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-name" type="text" autocomplete="name" placeholder="Ada Lovelace" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<div class="mb-4.5">
<label for="lgt-07-email" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Email</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-email" type="email" autocomplete="email" placeholder="ada@studio.dev" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<div class="mb-4.5">
<label for="lgt-07-pass" class="mb-1.75 block text-xs font-semibold uppercase tracking-[0.06em] text-white/70">Password</label>
<span class="relative block before:pointer-events-none before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5 before:opacity-0 before:transition-opacity before:duration-300 before:[background:conic-gradient(from_var(--lgt-07-angle),var(--color-lgt07-accent),oklch(0.7_0.18_200),oklch(0.72_0.17_330),var(--color-lgt07-accent))] before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)] before:[mask-clip:content-box,border-box] before:[mask-composite:exclude] focus-within:before:opacity-100 focus-within:before:animate-lgt07-spin motion-reduce:focus-within:before:animate-none">
<input id="lgt-07-pass" type="password" autocomplete="new-password" placeholder="••••••••" class="relative z-1 block w-full rounded-[14px] border border-white/25 bg-white/8 px-3.75 py-3.25 text-[15px] text-white outline-none backdrop-blur-[8px] shadow-[inset_0_1px_0_rgba(255,255,255,.3)] transition-colors duration-200 placeholder:text-white/50 focus:bg-white/14">
</span>
</div>
<button type="submit" class="mt-1.5 w-full cursor-pointer rounded-[14px] border border-lgt07-accent/60 bg-linear-to-b from-lgt07-accent-top to-lgt07-accent py-3.5 text-base font-bold text-white shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_14px_28px_-16px_rgba(0,0,0,.6)] transition-transform duration-150 hover:-translate-y-0.5 focus-visible:-translate-y-0.5 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white motion-reduce:transition-none">Sign up</button>
</form>
</section>
```
## CSS
```css
@import "tailwindcss";
/* Not portable to a utility, and must not be dropped: registering the angle as an
<angle> is what lets the browser interpolate it instead of snapping. */
@property --lgt-07-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-lgt07-accent: #8b5cf6;
--color-lgt07-accent: oklch(0.68 0.19 285);
--color-lgt07-accent-top: #a78bfa;
--color-lgt07-accent-top: oklch(0.74 0.16 285);
--font-lgt07-sans: 'Manrope', system-ui, sans-serif;
--animate-lgt07-spin: lgt-07-spin 3s linear infinite;
}
@keyframes lgt-07-spin {
to {
--lgt-07-angle: 360deg;
}
}
```How this works
The rim is a masked gradient, and it ports cleanly. A before: layer inset by 2px paints the conic gradient, then two masks composited with exclude punch out the middle so only a 2px rim survives. It looks exotic; as utilities it is four arbitrary values on one element:
before:absolute before:-inset-0.5 before:rounded-[16px] before:p-0.5
before:[background:conic-gradient(from_var(--lgt-07-angle),...)]
before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)]
before:[mask-clip:content-box,border-box]
before:[mask-composite:exclude]@property is the part that cannot leave. Without registering --lgt-07-angle as an <angle>, the browser treats it as an opaque string and the conic gradient snaps between values instead of rotating. There is no utility for a property registration, and there should not be — it is a type declaration, not a style.
focus-within: is the whole state machine. The wrapper lights its rim, the input lifts its tint, and both are driven by the browser's own notion of 'something inside me has focus'. No JS, no focus/blur handlers, no state.
Labels stay real. Every field is a genuine <label for> plus input pair with a matching autocomplete token, because a glass form that browsers cannot autofill is a worse form.
Make it yours
- Recolour the travelling rim by editing the conic gradient's stops; three hues around the wheel reads as refraction, more than four reads as a rainbow.
- Slow the spin to
6sin the--animate-lgt07-spinentry for a calmer, more expensive feel. - Make the rim static by dropping the
focus-within:before:animate-*utility and keeping the gradient — still a clear focus affordance, zero animation cost. - Adjust the frost per field with
backdrop-blur-[8px]; heavier blur on inputs hurts legibility fast. - Add validation states as
user-invalid:variants, which key off the browser's own constraint validation rather than a JS class.
Gotchas — read before shipping
@propertyis load-bearing. Drop it in the port and the border stops animating with no error — the gradient simply jumps.- Use
mask-image+mask-clip, not themaskshorthand. Tailwind emits each arbitrary property as its own rule and the shorthand can land aftermask-composite, resetting it toadd— at which point the gradient fills the whole box and sits behind your text as a coloured slab. outline-noneon an input is only acceptable if you replace the affordance visibly elsewhere. Here the wrapper's lit rim does that job.- Arbitrary values with commas inside functions are fine, but every space must be an underscore —
conic-gradient(from_var(--a),#fff,#000). - An always-spinning border on an unfocused form is a distraction; the animation is deliberately scoped to
focus-withinonly. - Input text must stay full-opacity white.
text-white/70over a frosted tile is the classic way glass forms fail WCAG.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
@property (Chrome 85+, Safari 16.4+, Firefox 128+) is what animates the rim, and it sets the same floor Tailwind v4 does. Where it is missing the field shows a static glowing ring on focus — same affordance, no rotation.