Pure TailwindMIT licensed

Tailwind Underline Sweep Input

A hairline underline that draws outward from the centre on focus. The whole effect is one element and one variant: an after: bar pinned at left-1/2 right-1/2, released to focus-within:after:inset-x-0.

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

<div class="tif-02 grid min-h-svh w-full place-items-center bg-tif02-bg px-6 py-14 font-tif02-sans" aria-label="Underline sweep input demo">
  <label class="grid w-full max-w-70 gap-1.5">
    <span class="text-[11px] tracking-[0.08em] text-tif02-mut uppercase">Username</span>
    <span class="relative block border-b border-white/14 after:absolute after:bottom-[-1px] after:left-1/2 after:right-1/2 after:h-0.5 after:bg-linear-to-r after:from-tif02-acc after:to-tif02-acc2 after:transition-[left,right] after:duration-300 after:ease-out after:content-[''] focus-within:after:inset-x-0 motion-reduce:after:transition-none">
      <input type="text" name="tif02-user" autocomplete="username" placeholder="@codefronts" required
        class="w-full appearance-none border-0 bg-transparent py-2 text-sm text-tif02-ink outline-none placeholder:text-tif02-mut">
    </span>
  </label>
</div>
@import "tailwindcss";

@theme {
  --color-tif02-bg: #12121a;
  --color-tif02-bg: oklch(0.19 0.015 285);
  --color-tif02-ink: #f0eeff;
  --color-tif02-ink: oklch(0.95 0.02 290);
  --color-tif02-mut: #b8b6d4;
  --color-tif02-mut: oklch(0.77 0.03 290);
  --color-tif02-acc: #ff6c8a;
  --color-tif02-acc: oklch(0.72 0.17 15);
  --color-tif02-acc2: #ff9a76;
  --color-tif02-acc2: oklch(0.78 0.14 45);
  --font-tif02-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}

.tif-02 {
  width: 100%;
}

.tif-02 ::selection {
  background: var(--color-tif02-acc);
  color: #12121a;
}

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-tif02-bg: #12121a;
  --color-tif02-bg: oklch(0.19 0.015 285);
  --color-tif02-ink: #f0eeff;
  --color-tif02-ink: oklch(0.95 0.02 290);
  --color-tif02-mut: #b8b6d4;
  --color-tif02-mut: oklch(0.77 0.03 290);
  --color-tif02-acc: #ff6c8a;
  --color-tif02-acc: oklch(0.72 0.17 15);
  --color-tif02-acc2: #ff9a76;
  --color-tif02-acc2: oklch(0.78 0.14 45);
  --font-tif02-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}

.tif-02 {
  width: 100%;
}

.tif-02 ::selection {
  background: var(--color-tif02-acc);
  color: #12121a;
}
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=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap">

What changed in the port

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

  • The .wrap::after rule and its :focus-within partner become one class list on the wrapper — the only place in the port where after: and a variant stack four levels deep and still read cleanly.
  • appearance-none was a gotcha note in the CSS original; here it is simply on the element.
  • The gradient uses the bg-linear-to-r from-* to-* trio rather than an arbitrary linear-gradient(), so both stops are themeable tokens.
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 Underline Sweep Input
Source: https://codefronts.com/components/tailwind-css-input-fields/tailwind-underline-sweep-input/

A hairline underline that draws outward from the centre on focus. The whole effect is one element and one variant: an after: bar pinned at left-1/2 right-1/2, released to focus-within:after:inset-x-0.
## HTML
```html
<div class="tif-02 grid min-h-svh w-full place-items-center bg-tif02-bg px-6 py-14 font-tif02-sans" aria-label="Underline sweep input demo">
  <label class="grid w-full max-w-70 gap-1.5">
    <span class="text-[11px] tracking-[0.08em] text-tif02-mut uppercase">Username</span>
    <span class="relative block border-b border-white/14 after:absolute after:bottom-[-1px] after:left-1/2 after:right-1/2 after:h-0.5 after:bg-linear-to-r after:from-tif02-acc after:to-tif02-acc2 after:transition-[left,right] after:duration-300 after:ease-out after:content-[''] focus-within:after:inset-x-0 motion-reduce:after:transition-none">
      <input type="text" name="tif02-user" autocomplete="username" placeholder="@codefronts" required
        class="w-full appearance-none border-0 bg-transparent py-2 text-sm text-tif02-ink outline-none placeholder:text-tif02-mut">
    </span>
  </label>
</div>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tif02-bg: #12121a;
  --color-tif02-bg: oklch(0.19 0.015 285);
  --color-tif02-ink: #f0eeff;
  --color-tif02-ink: oklch(0.95 0.02 290);
  --color-tif02-mut: #b8b6d4;
  --color-tif02-mut: oklch(0.77 0.03 290);
  --color-tif02-acc: #ff6c8a;
  --color-tif02-acc: oklch(0.72 0.17 15);
  --color-tif02-acc2: #ff9a76;
  --color-tif02-acc2: oklch(0.78 0.14 45);
  --font-tif02-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}

.tif-02 {
  width: 100%;
}

.tif-02 ::selection {
  background: var(--color-tif02-acc);
  color: #12121a;
}
```

How this works

Closed and open live side by side. The bar is a pseudo-element with zero width by default, and the focus state only has to release the two insets:

class="after:absolute after:bottom-[-1px] after:left-1/2 after:right-1/2
  after:h-0.5 after:content-[''] focus-within:after:inset-x-0"

The wrapper is not optional. after: needs a positioned ancestor and focus-within: needs something to be within — the same two reasons the CSS version keeps its wrapper span. Utilities do not remove structural requirements; they just put the reason next to the element.

Make it yours

  • Colour: the two @theme stops, or drop to a single after:bg-tif02-acc for a flat bar.
  • Speed: after:duration-300. One value now drives both edges, so symmetry is automatic.
  • Reverse it (edges to centre): start at after:inset-x-0 and focus to focus-within:after:left-1/2 focus-within:after:right-1/2.
  • Weight: after:h-0.5 → after:h-[3px], and darken the resting border-white/14 on light grounds.

Gotchas — read before shipping

  • Remove the wrapper and the effect dies twice over: no positioning context, nothing for focus-within to attach to.
  • focus-within fires for any focusable descendant — add a submit icon button inside and it sweeps on that too.
  • The bar sits at after:bottom-[-1px] to cover the 1px resting border; change one and you must change the other.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

:focus-within is Baseline; without it the bar simply stays collapsed and invisible.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Theme tokensset in @theme, used by a utility

Search CodeFronts

Loading…