16 / 30
All 30 in 30 Tailwind CSS Text Hover Effects
- 01Tailwind CSS Animated Underline Hover Effect
- 02Tailwind Liquid Text Fill Hover Animation
- 03Tailwind Gradient Text Hover Effect with bg-clip-text
- 04Tailwind Animated Strikethrough Text Hover Effect
- 05Tailwind Text Swap and Flip Up Hover Effect
- 06Tailwind CSS Glitch Text Hover Effect
- 07Tailwind Neon Glow Text with Flicker Animation
- 08Tailwind Metallic Gold Shimmer Text Effect
- 09Tailwind 3D Text Pop and Lift Hover Effect
- 10Tailwind Staggered Letter Wave Hover Animation
- 11Tailwind Spotlight Text Reveal on Mouse Hover
- 12Tailwind Hover to Reveal Hidden Spoiler Text
- 13Tailwind Blur to Focus Text Hover Effect
- 14Tailwind Magnetic Hover Effect for Buttons and Text
- 15Tailwind Letter Spacing Expand on Hover (Tracking Animation)
- 16Tailwind Outline Text Stroke to Fill Hover Effect
- 17Tailwind Text Scramble and Matrix Decrypt Hover Effect
- 18Tailwind Animated Border Button Hover Effect
- 19Tailwind Elastic Rubber Band Text Hover Animation
- 20Tailwind Variable Font Weight Hover Animation
- 21Tailwind Animated Rainbow Gradient Text on Hover
- 22Tailwind 3D Perspective Tilt Text Hover Effect
- 23Tailwind Smoke Dissolve Text Hover Effect
- 24Tailwind Fire Text Effect with Heat Wave Glow
- 25Tailwind Dynamic Text Shadow that Follows the Cursor
- 26Tailwind Infinite Text Marquee that Speeds Up on Hover
- 27Tailwind Duotone Split Color Text Hover Effect
- 28Tailwind CSS Tooltip on Hover (No JavaScript)
- 29Tailwind SVG Water Ripple Distortion Text Effect
- 30Tailwind Clip-Path Text Reveal Hover Animation
Tailwind Outline Text Stroke to Fill Hover Effect
A foundry wordmark that pours from outline to solid: one element carries both the stroke ([-webkit-text-stroke:…]) and a gradient clipped to the glyphs whose height grows bg-[length:100%_0%] → hover:bg-[length:100%_100%] from the baseline. The nav bars fill left to right with the same two utilities rotated.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tth-16 @container w-full min-h-svh grid place-items-center bg-tth16-bg bg-[radial-gradient(90%_70%_at_50%_100%,var(--color-tth16-glow),var(--color-tth16-bg)_70%)] px-5 py-14 font-tth16-sans text-tth16-ink" aria-label="Outline to fill text demo">
<div class="flex w-full max-w-[47.5rem] flex-col items-center gap-[clamp(20px,3.6cqi,32px)] text-center">
<header class="flex w-full flex-wrap items-center justify-between gap-3.5 border-b border-tth16-line pb-3.5">
<p class="text-xs font-bold uppercase tracking-[0.22em] text-tth16-mut">Grade 900 — a display face in 5 weights</p>
<span class="rounded-full border border-tth16-heat2/40 px-3 py-1.5 font-tth16-mono text-[11px] text-tth16-heat2 @max-[35rem]:hidden">bg-[length:100%_0%] → 100%_100%</span>
</header>
<a id="tth16-top" href="#tth16-top" class="inline-block rounded-md px-[0.06em] py-[0.08em] font-tth16-display text-[clamp(84px,20cqi,210px)] uppercase leading-none tracking-[0.02em] no-underline text-transparent [-webkit-text-stroke:1.5px_color-mix(in_oklch,var(--color-tth16-ink)_65%,transparent)] bg-[linear-gradient(15deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_100%] bg-[length:100%_0%] bg-clip-text transition-[background-size,-webkit-text-stroke-color] duration-600 ease-[cubic-bezier(.3,.85,.2,1)] hover:bg-[length:100%_100%] hover:[-webkit-text-stroke-color:color-mix(in_oklch,var(--color-tth16-heat1)_60%,transparent)] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[10px] focus-visible:outline-tth16-heat2 pointer-coarse:bg-[length:100%_100%] motion-reduce:transition-none">FORGE</a>
<nav class="flex flex-wrap justify-center gap-[clamp(10px,2.4cqi,20px)]" aria-label="Foundry">
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Trial fonts</a>
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Licensing</a>
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Specimens</a>
</nav>
<p class="max-w-[56ch] text-[12.5px] leading-[1.7] text-tth16-mut">Hover the wordmark: the fill pours up from the baseline through <code class="rounded bg-tth16-chip px-1.5 py-px font-tth16-mono text-[0.9em] text-tth16-heat2">bg-clip-text</code> — one element, stroke and fill on separate paint channels.</p>
</div>
</section><section class="tth-16 @container w-full min-h-svh grid place-items-center bg-tth16-bg bg-[radial-gradient(90%_70%_at_50%_100%,var(--color-tth16-glow),var(--color-tth16-bg)_70%)] px-5 py-14 font-tth16-sans text-tth16-ink" aria-label="Outline to fill text demo">
<div class="flex w-full max-w-[47.5rem] flex-col items-center gap-[clamp(20px,3.6cqi,32px)] text-center">
<header class="flex w-full flex-wrap items-center justify-between gap-3.5 border-b border-tth16-line pb-3.5">
<p class="text-xs font-bold uppercase tracking-[0.22em] text-tth16-mut">Grade 900 — a display face in 5 weights</p>
<span class="rounded-full border border-tth16-heat2/40 px-3 py-1.5 font-tth16-mono text-[11px] text-tth16-heat2 @max-[35rem]:hidden">bg-[length:100%_0%] → 100%_100%</span>
</header>
<a id="tth16-top" href="#tth16-top" class="inline-block rounded-md px-[0.06em] py-[0.08em] font-tth16-display text-[clamp(84px,20cqi,210px)] uppercase leading-none tracking-[0.02em] no-underline text-transparent [-webkit-text-stroke:1.5px_color-mix(in_oklch,var(--color-tth16-ink)_65%,transparent)] bg-[linear-gradient(15deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_100%] bg-[length:100%_0%] bg-clip-text transition-[background-size,-webkit-text-stroke-color] duration-600 ease-[cubic-bezier(.3,.85,.2,1)] hover:bg-[length:100%_100%] hover:[-webkit-text-stroke-color:color-mix(in_oklch,var(--color-tth16-heat1)_60%,transparent)] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[10px] focus-visible:outline-tth16-heat2 pointer-coarse:bg-[length:100%_100%] motion-reduce:transition-none">FORGE</a>
<nav class="flex flex-wrap justify-center gap-[clamp(10px,2.4cqi,20px)]" aria-label="Foundry">
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Trial fonts</a>
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Licensing</a>
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Specimens</a>
</nav>
<p class="max-w-[56ch] text-[12.5px] leading-[1.7] text-tth16-mut">Hover the wordmark: the fill pours up from the baseline through <code class="rounded bg-tth16-chip px-1.5 py-px font-tth16-mono text-[0.9em] text-tth16-heat2">bg-clip-text</code> — one element, stroke and fill on separate paint channels.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tth16-bg: #15120e;
--color-tth16-bg: oklch(0.18 0.008 60);
--color-tth16-glow: #221a12;
--color-tth16-glow: oklch(0.23 0.02 55);
--color-tth16-chip: #2a241d;
--color-tth16-chip: oklch(0.27 0.012 60);
--color-tth16-ink: #eee9e1;
--color-tth16-ink: oklch(0.93 0.008 75);
--color-tth16-mut: #a59d92;
--color-tth16-mut: oklch(0.72 0.015 70);
--color-tth16-heat1: #f07a32;
--color-tth16-heat1: oklch(0.72 0.18 45);
--color-tth16-heat2: #f7c84a;
--color-tth16-heat2: oklch(0.85 0.15 80);
--color-tth16-line: #3a332b;
--color-tth16-line: oklch(0.32 0.012 65);
--font-tth16-display: 'Anton', Impact, sans-serif;
--font-tth16-sans: 'Work Sans', system-ui, sans-serif;
--font-tth16-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-16 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tth16-bg: #15120e;
--color-tth16-bg: oklch(0.18 0.008 60);
--color-tth16-glow: #221a12;
--color-tth16-glow: oklch(0.23 0.02 55);
--color-tth16-chip: #2a241d;
--color-tth16-chip: oklch(0.27 0.012 60);
--color-tth16-ink: #eee9e1;
--color-tth16-ink: oklch(0.93 0.008 75);
--color-tth16-mut: #a59d92;
--color-tth16-mut: oklch(0.72 0.015 70);
--color-tth16-heat1: #f07a32;
--color-tth16-heat1: oklch(0.72 0.18 45);
--color-tth16-heat2: #f7c84a;
--color-tth16-heat2: oklch(0.85 0.15 80);
--color-tth16-line: #3a332b;
--color-tth16-line: oklch(0.32 0.012 65);
--font-tth16-display: 'Anton', Impact, sans-serif;
--font-tth16-sans: 'Work Sans', system-ui, sans-serif;
--font-tth16-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-16 {
width: 100%;
min-height: 100svh;
}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";
@theme {
--color-tth16-bg: #15120e;
--color-tth16-bg: oklch(0.18 0.008 60);
--color-tth16-glow: #221a12;
--color-tth16-glow: oklch(0.23 0.02 55);
--color-tth16-chip: #2a241d;
--color-tth16-chip: oklch(0.27 0.012 60);
--color-tth16-ink: #eee9e1;
--color-tth16-ink: oklch(0.93 0.008 75);
--color-tth16-mut: #a59d92;
--color-tth16-mut: oklch(0.72 0.015 70);
--color-tth16-heat1: #f07a32;
--color-tth16-heat1: oklch(0.72 0.18 45);
--color-tth16-heat2: #f7c84a;
--color-tth16-heat2: oklch(0.85 0.15 80);
--color-tth16-line: #3a332b;
--color-tth16-line: oklch(0.32 0.012 65);
--font-tth16-display: 'Anton', Impact, sans-serif;
--font-tth16-sans: 'Work Sans', system-ui, sans-serif;
--font-tth16-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-16 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tth16-bg: #15120e;
--color-tth16-bg: oklch(0.18 0.008 60);
--color-tth16-glow: #221a12;
--color-tth16-glow: oklch(0.23 0.02 55);
--color-tth16-chip: #2a241d;
--color-tth16-chip: oklch(0.27 0.012 60);
--color-tth16-ink: #eee9e1;
--color-tth16-ink: oklch(0.93 0.008 75);
--color-tth16-mut: #a59d92;
--color-tth16-mut: oklch(0.72 0.015 70);
--color-tth16-heat1: #f07a32;
--color-tth16-heat1: oklch(0.72 0.18 45);
--color-tth16-heat2: #f7c84a;
--color-tth16-heat2: oklch(0.85 0.15 80);
--color-tth16-line: #3a332b;
--color-tth16-line: oklch(0.32 0.012 65);
--font-tth16-display: 'Anton', Impact, sans-serif;
--font-tth16-sans: 'Work Sans', system-ui, sans-serif;
--font-tth16-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-16 {
width: 100%;
min-height: 100svh;
}<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=Anton&family=Work+Sans:wght@400..800&family=JetBrains+Mono:wght@400;600&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=Anton&family=Work+Sans:wght@400..800&family=JetBrains+Mono:wght@400;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The
.hollowand.barrules became two class lists;-webkit-text-stroke-coloris animated through an arbitrary property insidetransition-[…]. - UI upgrade from the CSS original: a 900-weight system font draws visible contour seams through a stroke; Anton is a static condensed face, so FORGE renders as clean, single outlines — and condensed lets it run 20% bigger.
- UI upgrade: nav labels grew from 15px to 18px with a stronger 85% stroke, so the hollow state is readable, and touch screens see the wordmark filled (
pointer-coarse:).
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 Outline Text Stroke to Fill Hover Effect
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-outline-text-stroke-to-fill-hover-effect/
A foundry wordmark that pours from outline to solid: one element carries both the stroke ([-webkit-text-stroke:…]) and a gradient clipped to the glyphs whose height grows bg-[length:100%_0%] → hover:bg-[length:100%_100%] from the baseline. The nav bars fill left to right with the same two utilities rotated.
## HTML
```html
<section class="tth-16 @container w-full min-h-svh grid place-items-center bg-tth16-bg bg-[radial-gradient(90%_70%_at_50%_100%,var(--color-tth16-glow),var(--color-tth16-bg)_70%)] px-5 py-14 font-tth16-sans text-tth16-ink" aria-label="Outline to fill text demo">
<div class="flex w-full max-w-[47.5rem] flex-col items-center gap-[clamp(20px,3.6cqi,32px)] text-center">
<header class="flex w-full flex-wrap items-center justify-between gap-3.5 border-b border-tth16-line pb-3.5">
<p class="text-xs font-bold uppercase tracking-[0.22em] text-tth16-mut">Grade 900 — a display face in 5 weights</p>
<span class="rounded-full border border-tth16-heat2/40 px-3 py-1.5 font-tth16-mono text-[11px] text-tth16-heat2 @max-[35rem]:hidden">bg-[length:100%_0%] → 100%_100%</span>
</header>
<a id="tth16-top" href="#tth16-top" class="inline-block rounded-md px-[0.06em] py-[0.08em] font-tth16-display text-[clamp(84px,20cqi,210px)] uppercase leading-none tracking-[0.02em] no-underline text-transparent [-webkit-text-stroke:1.5px_color-mix(in_oklch,var(--color-tth16-ink)_65%,transparent)] bg-[linear-gradient(15deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_100%] bg-[length:100%_0%] bg-clip-text transition-[background-size,-webkit-text-stroke-color] duration-600 ease-[cubic-bezier(.3,.85,.2,1)] hover:bg-[length:100%_100%] hover:[-webkit-text-stroke-color:color-mix(in_oklch,var(--color-tth16-heat1)_60%,transparent)] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[10px] focus-visible:outline-tth16-heat2 pointer-coarse:bg-[length:100%_100%] motion-reduce:transition-none">FORGE</a>
<nav class="flex flex-wrap justify-center gap-[clamp(10px,2.4cqi,20px)]" aria-label="Foundry">
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Trial fonts</a>
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Licensing</a>
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Specimens</a>
</nav>
<p class="max-w-[56ch] text-[12.5px] leading-[1.7] text-tth16-mut">Hover the wordmark: the fill pours up from the baseline through <code class="rounded bg-tth16-chip px-1.5 py-px font-tth16-mono text-[0.9em] text-tth16-heat2">bg-clip-text</code> — one element, stroke and fill on separate paint channels.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tth16-bg: #15120e;
--color-tth16-bg: oklch(0.18 0.008 60);
--color-tth16-glow: #221a12;
--color-tth16-glow: oklch(0.23 0.02 55);
--color-tth16-chip: #2a241d;
--color-tth16-chip: oklch(0.27 0.012 60);
--color-tth16-ink: #eee9e1;
--color-tth16-ink: oklch(0.93 0.008 75);
--color-tth16-mut: #a59d92;
--color-tth16-mut: oklch(0.72 0.015 70);
--color-tth16-heat1: #f07a32;
--color-tth16-heat1: oklch(0.72 0.18 45);
--color-tth16-heat2: #f7c84a;
--color-tth16-heat2: oklch(0.85 0.15 80);
--color-tth16-line: #3a332b;
--color-tth16-line: oklch(0.32 0.012 65);
--font-tth16-display: 'Anton', Impact, sans-serif;
--font-tth16-sans: 'Work Sans', system-ui, sans-serif;
--font-tth16-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-16 {
width: 100%;
min-height: 100svh;
}
```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 Outline Text Stroke to Fill Hover Effect
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-outline-text-stroke-to-fill-hover-effect/
A foundry wordmark that pours from outline to solid: one element carries both the stroke ([-webkit-text-stroke:…]) and a gradient clipped to the glyphs whose height grows bg-[length:100%_0%] → hover:bg-[length:100%_100%] from the baseline. The nav bars fill left to right with the same two utilities rotated.
## HTML
```html
<section class="tth-16 @container w-full min-h-svh grid place-items-center bg-tth16-bg bg-[radial-gradient(90%_70%_at_50%_100%,var(--color-tth16-glow),var(--color-tth16-bg)_70%)] px-5 py-14 font-tth16-sans text-tth16-ink" aria-label="Outline to fill text demo">
<div class="flex w-full max-w-[47.5rem] flex-col items-center gap-[clamp(20px,3.6cqi,32px)] text-center">
<header class="flex w-full flex-wrap items-center justify-between gap-3.5 border-b border-tth16-line pb-3.5">
<p class="text-xs font-bold uppercase tracking-[0.22em] text-tth16-mut">Grade 900 — a display face in 5 weights</p>
<span class="rounded-full border border-tth16-heat2/40 px-3 py-1.5 font-tth16-mono text-[11px] text-tth16-heat2 @max-[35rem]:hidden">bg-[length:100%_0%] → 100%_100%</span>
</header>
<a id="tth16-top" href="#tth16-top" class="inline-block rounded-md px-[0.06em] py-[0.08em] font-tth16-display text-[clamp(84px,20cqi,210px)] uppercase leading-none tracking-[0.02em] no-underline text-transparent [-webkit-text-stroke:1.5px_color-mix(in_oklch,var(--color-tth16-ink)_65%,transparent)] bg-[linear-gradient(15deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_100%] bg-[length:100%_0%] bg-clip-text transition-[background-size,-webkit-text-stroke-color] duration-600 ease-[cubic-bezier(.3,.85,.2,1)] hover:bg-[length:100%_100%] hover:[-webkit-text-stroke-color:color-mix(in_oklch,var(--color-tth16-heat1)_60%,transparent)] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[10px] focus-visible:outline-tth16-heat2 pointer-coarse:bg-[length:100%_100%] motion-reduce:transition-none">FORGE</a>
<nav class="flex flex-wrap justify-center gap-[clamp(10px,2.4cqi,20px)]" aria-label="Foundry">
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Trial fonts</a>
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Licensing</a>
<a href="#tth16-top" class="grid min-h-12 place-items-center rounded-[10px] border-[1.5px] border-tth16-line px-6 font-tth16-display text-lg uppercase tracking-[0.06em] no-underline text-transparent [-webkit-text-stroke:1px_color-mix(in_oklch,var(--color-tth16-ink)_85%,transparent)] bg-[linear-gradient(90deg,var(--color-tth16-heat1),var(--color-tth16-heat2))] bg-no-repeat bg-[position:0_0] bg-[length:0%_100%] bg-clip-text transition-[background-size,border-color] duration-450 ease-[cubic-bezier(.3,.85,.2,1)] hover:border-tth16-heat1/60 hover:bg-[length:100%_100%] focus-visible:bg-[length:100%_100%] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-tth16-heat2 motion-reduce:transition-none">Specimens</a>
</nav>
<p class="max-w-[56ch] text-[12.5px] leading-[1.7] text-tth16-mut">Hover the wordmark: the fill pours up from the baseline through <code class="rounded bg-tth16-chip px-1.5 py-px font-tth16-mono text-[0.9em] text-tth16-heat2">bg-clip-text</code> — one element, stroke and fill on separate paint channels.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tth16-bg: #15120e;
--color-tth16-bg: oklch(0.18 0.008 60);
--color-tth16-glow: #221a12;
--color-tth16-glow: oklch(0.23 0.02 55);
--color-tth16-chip: #2a241d;
--color-tth16-chip: oklch(0.27 0.012 60);
--color-tth16-ink: #eee9e1;
--color-tth16-ink: oklch(0.93 0.008 75);
--color-tth16-mut: #a59d92;
--color-tth16-mut: oklch(0.72 0.015 70);
--color-tth16-heat1: #f07a32;
--color-tth16-heat1: oklch(0.72 0.18 45);
--color-tth16-heat2: #f7c84a;
--color-tth16-heat2: oklch(0.85 0.15 80);
--color-tth16-line: #3a332b;
--color-tth16-line: oklch(0.32 0.012 65);
--font-tth16-display: 'Anton', Impact, sans-serif;
--font-tth16-sans: 'Work Sans', system-ui, sans-serif;
--font-tth16-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-16 {
width: 100%;
min-height: 100svh;
}
```How this works
Stroke and fill don't fight. -webkit-text-stroke paints the outline; background-clip:text paints whatever background is behind the glyph shapes. Both live on one element, so there's no duplicate layer to keep in sync:
<a class="text-transparent [-webkit-text-stroke:1.5px_…]
bg-[linear-gradient(15deg,…)] bg-no-repeat bg-[position:0_100%]
bg-[length:100%_0%] bg-clip-text
transition-[background-size,-webkit-text-stroke-color] duration-600
hover:bg-[length:100%_100%]">Direction is the anchor. Anchored at the bottom and sized vertically, the fill rises; the nav bars anchor at the left and size horizontally, so they wipe across.
Font choice matters. Variable fonts overlap their contours internally, and a plain stroke reveals those seams. Anton is a static face with clean outlines.
Make it yours
- Wipe direction:
bg-[position:0_0]+bg-[length:0%_100%]for left-to-right on the wordmark. - Solid fill: replace the gradient with
bg-[linear-gradient(var(--color-tth16-heat1),var(--color-tth16-heat1))]. - Thicker outline: raise the stroke to
2.5pxat display sizes.
Gotchas — read before shipping
-webkit-text-strokestraddles the glyph edge — half is inside, so very thick strokes eat counters.- With a variable font, use
[paint-order:stroke_fill]and a solid fill, or load a static instance. - Stroked small text is low-contrast; keep it ≥ 16px with a ≥ 1px stroke.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
-webkit-text-stroke is supported unprefixed-in-practice by all engines.