11 / 30
All 30 in 30 Tailwind CSS Login Forms
- 01Tailwind Split-Screen Brand Hero Login Form
- 02Tailwind Multi-Tenant Workspace Account Switcher
- 03Tailwind Floating Label Login Form with peer Variants
- 04Tailwind Web3 Wallet Connect Login Grid
- 05Tailwind Minimalist Fintech Login Card with Layered Shadow
- 06Tailwind OAuth Social Login Form with Brand SVG Buttons
- 07Tailwind Passwordless Magic Link Login with data-state Machine
- 08Tailwind Aurora Glow Login Card with Drifting Blur Blobs
- 09Tailwind Neon Synthwave Arcade Login Form
- 10Tailwind Sliding Login and Sign Up Panel with peer-checked
- 11Tailwind 3D Flip Login Card with Password Reset Back Face
- 12Tailwind Terminal CLI Prompt Login Form
- 13Tailwind Floating Pill Login Widget Docked Over App Content
- 14Tailwind Gradient Border Login Card with background-clip
- 15Tailwind Slide-Over Side Panel Login without JavaScript
- 16Tailwind Social-First Sign Up with Brand-Compliant Buttons
- 17Tailwind Animated Mascot Login that Covers Its Eyes
- 18Tailwind Accessible Compact Login Modal with Scale-In
- 19Tailwind Glassmorphism Login Card with backdrop-filter
- 20Tailwind Multi-Step Login Wizard with Radio-Driven Track
- 21Tailwind Animated Conic Gradient Border Login Card
- 22Tailwind Secure Vault Login with user-invalid Error State
- 23Tailwind Neo-Brutalist Login Form with Hard Offset Shadow
- 24Tailwind Show Hide Password Toggle with aria-pressed
- 25Tailwind OTP Code Input Grid with Auto-Advance
- 26Tailwind Password Strength Meter with data-score Variants
- 27Tailwind Numeric PIN Pad Login for Kiosks and POS
- 28Tailwind Inline Form Validation with user-valid and user-invalid
- 29Tailwind Particle Constellation Login over Canvas
- 30Tailwind Biometric Face ID Prompt with Pulse Ripples
Tailwind 3D Flip Login Card with Password Reset Back Face
Forgot Password lives on the back of the login card: tick a hidden checkbox and the whole card rotates in 3D to reveal the recovery form — no redirect, no bleed-through. v4 makes this port unusually clean, because rotate-y-180, backface-hidden, transform-3d and perspective-[1400px] are all real utilities now.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tlf-11 w-full min-h-svh grid place-items-center bg-tlf11-stage font-tlf11-sans p-6">
<div class="relative w-[min(380px,100%)] perspective-[1400px]">
<input type="checkbox" id="tlf-11-flip" aria-label="Show password reset form" class="peer sr-only">
<div class="relative w-full min-h-[420px] transform-3d transition-transform duration-700 ease-[cubic-bezier(0.4,0,0.2,1)] peer-checked:rotate-y-180 peer-focus-visible:outline-3 peer-focus-visible:outline-offset-[6px] peer-focus-visible:outline-tlf11-ring peer-focus-visible:rounded-[18px] motion-reduce:duration-0">
<form novalidate class="absolute inset-0 backface-hidden flex flex-col gap-3 p-8 bg-white border border-tlf11-edge rounded-[18px] shadow-[0_24px_56px_-38px_oklch(0.35_0.06_50/0.5)]">
<h2 class="mb-1 text-[23px] font-bold text-tlf11-ink">Sign in</h2>
<input type="email" placeholder="Email" autocomplete="email" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<input type="password" placeholder="Password" autocomplete="current-password" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<button type="submit" class="h-12 rounded-xl border-0 cursor-pointer bg-tlf11-acc text-white text-[15px] font-semibold transition-[filter,scale] duration-150 hover:brightness-110 active:scale-[0.985] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tlf11-ring motion-reduce:transition-none motion-reduce:active:scale-100">Log in</button>
<label for="tlf-11-flip" class="grid place-items-center self-center min-h-11 px-2 text-[13px] font-semibold text-tlf11-acc cursor-pointer hover:underline">Forgot password?</label>
</form>
<form novalidate class="absolute inset-0 backface-hidden rotate-y-180 flex flex-col gap-3 p-8 bg-white border border-tlf11-edge rounded-[18px] shadow-[0_24px_56px_-38px_oklch(0.35_0.06_50/0.5)]">
<h2 class="text-[23px] font-bold text-tlf11-ink">Reset password</h2>
<p class="-mt-1.5 mb-1 text-[13.5px]/[1.5] text-tlf11-mut">Enter your email and we’ll send a reset link.</p>
<input type="email" placeholder="Email" autocomplete="email" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<button type="submit" class="h-12 rounded-xl border-0 cursor-pointer bg-tlf11-acc text-white text-[15px] font-semibold transition-[filter,scale] duration-150 hover:brightness-110 active:scale-[0.985] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tlf11-ring motion-reduce:transition-none motion-reduce:active:scale-100">Send link</button>
<label for="tlf-11-flip" class="grid place-items-center self-center min-h-11 px-2 text-[13px] font-semibold text-tlf11-acc cursor-pointer hover:underline">← Back to sign in</label>
</form>
</div>
</div>
</section><section class="tlf-11 w-full min-h-svh grid place-items-center bg-tlf11-stage font-tlf11-sans p-6">
<div class="relative w-[min(380px,100%)] perspective-[1400px]">
<input type="checkbox" id="tlf-11-flip" aria-label="Show password reset form" class="peer sr-only">
<div class="relative w-full min-h-[420px] transform-3d transition-transform duration-700 ease-[cubic-bezier(0.4,0,0.2,1)] peer-checked:rotate-y-180 peer-focus-visible:outline-3 peer-focus-visible:outline-offset-[6px] peer-focus-visible:outline-tlf11-ring peer-focus-visible:rounded-[18px] motion-reduce:duration-0">
<form novalidate class="absolute inset-0 backface-hidden flex flex-col gap-3 p-8 bg-white border border-tlf11-edge rounded-[18px] shadow-[0_24px_56px_-38px_oklch(0.35_0.06_50/0.5)]">
<h2 class="mb-1 text-[23px] font-bold text-tlf11-ink">Sign in</h2>
<input type="email" placeholder="Email" autocomplete="email" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<input type="password" placeholder="Password" autocomplete="current-password" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<button type="submit" class="h-12 rounded-xl border-0 cursor-pointer bg-tlf11-acc text-white text-[15px] font-semibold transition-[filter,scale] duration-150 hover:brightness-110 active:scale-[0.985] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tlf11-ring motion-reduce:transition-none motion-reduce:active:scale-100">Log in</button>
<label for="tlf-11-flip" class="grid place-items-center self-center min-h-11 px-2 text-[13px] font-semibold text-tlf11-acc cursor-pointer hover:underline">Forgot password?</label>
</form>
<form novalidate class="absolute inset-0 backface-hidden rotate-y-180 flex flex-col gap-3 p-8 bg-white border border-tlf11-edge rounded-[18px] shadow-[0_24px_56px_-38px_oklch(0.35_0.06_50/0.5)]">
<h2 class="text-[23px] font-bold text-tlf11-ink">Reset password</h2>
<p class="-mt-1.5 mb-1 text-[13.5px]/[1.5] text-tlf11-mut">Enter your email and we’ll send a reset link.</p>
<input type="email" placeholder="Email" autocomplete="email" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<button type="submit" class="h-12 rounded-xl border-0 cursor-pointer bg-tlf11-acc text-white text-[15px] font-semibold transition-[filter,scale] duration-150 hover:brightness-110 active:scale-[0.985] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tlf11-ring motion-reduce:transition-none motion-reduce:active:scale-100">Send link</button>
<label for="tlf-11-flip" class="grid place-items-center self-center min-h-11 px-2 text-[13px] font-semibold text-tlf11-acc cursor-pointer hover:underline">← Back to sign in</label>
</form>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-tlf11-stage: #f5f2ef;
--color-tlf11-stage: oklch(0.96 0.008 60);
--color-tlf11-edge: #eadfd6;
--color-tlf11-edge: oklch(0.91 0.015 60);
--color-tlf11-fieldedge: #e0d3c8;
--color-tlf11-fieldedge: oklch(0.87 0.02 60);
--color-tlf11-field: #fdfbf9;
--color-tlf11-field: oklch(0.99 0.004 60);
--color-tlf11-ink: #2a1c12;
--color-tlf11-ink: oklch(0.25 0.03 50);
--color-tlf11-mut: #776154;
--color-tlf11-mut: oklch(0.52 0.03 50);
--color-tlf11-ph: #9a8577;
--color-tlf11-ph: oklch(0.63 0.03 50);
--color-tlf11-acc: #b1452a;
--color-tlf11-acc: oklch(0.53 0.17 30);
--color-tlf11-halo: #e9bdb0;
--color-tlf11-halo: oklch(0.53 0.17 30 / 0.16);
--color-tlf11-ring: #d9927f;
--color-tlf11-ring: oklch(0.53 0.17 30 / 0.5);
--font-tlf11-sans: 'Epilogue', system-ui, sans-serif;
}
.tlf-11 {
width: 100%;
min-height: 100svh;
}
/* Older WebKit still wants the prefixed backface property. */
.tlf-11 form {
-webkit-backface-visibility: hidden;
}@import "tailwindcss";
@theme {
--color-tlf11-stage: #f5f2ef;
--color-tlf11-stage: oklch(0.96 0.008 60);
--color-tlf11-edge: #eadfd6;
--color-tlf11-edge: oklch(0.91 0.015 60);
--color-tlf11-fieldedge: #e0d3c8;
--color-tlf11-fieldedge: oklch(0.87 0.02 60);
--color-tlf11-field: #fdfbf9;
--color-tlf11-field: oklch(0.99 0.004 60);
--color-tlf11-ink: #2a1c12;
--color-tlf11-ink: oklch(0.25 0.03 50);
--color-tlf11-mut: #776154;
--color-tlf11-mut: oklch(0.52 0.03 50);
--color-tlf11-ph: #9a8577;
--color-tlf11-ph: oklch(0.63 0.03 50);
--color-tlf11-acc: #b1452a;
--color-tlf11-acc: oklch(0.53 0.17 30);
--color-tlf11-halo: #e9bdb0;
--color-tlf11-halo: oklch(0.53 0.17 30 / 0.16);
--color-tlf11-ring: #d9927f;
--color-tlf11-ring: oklch(0.53 0.17 30 / 0.5);
--font-tlf11-sans: 'Epilogue', system-ui, sans-serif;
}
.tlf-11 {
width: 100%;
min-height: 100svh;
}
/* Older WebKit still wants the prefixed backface property. */
.tlf-11 form {
-webkit-backface-visibility: hidden;
}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-tlf11-stage: #f5f2ef;
--color-tlf11-stage: oklch(0.96 0.008 60);
--color-tlf11-edge: #eadfd6;
--color-tlf11-edge: oklch(0.91 0.015 60);
--color-tlf11-fieldedge: #e0d3c8;
--color-tlf11-fieldedge: oklch(0.87 0.02 60);
--color-tlf11-field: #fdfbf9;
--color-tlf11-field: oklch(0.99 0.004 60);
--color-tlf11-ink: #2a1c12;
--color-tlf11-ink: oklch(0.25 0.03 50);
--color-tlf11-mut: #776154;
--color-tlf11-mut: oklch(0.52 0.03 50);
--color-tlf11-ph: #9a8577;
--color-tlf11-ph: oklch(0.63 0.03 50);
--color-tlf11-acc: #b1452a;
--color-tlf11-acc: oklch(0.53 0.17 30);
--color-tlf11-halo: #e9bdb0;
--color-tlf11-halo: oklch(0.53 0.17 30 / 0.16);
--color-tlf11-ring: #d9927f;
--color-tlf11-ring: oklch(0.53 0.17 30 / 0.5);
--font-tlf11-sans: 'Epilogue', system-ui, sans-serif;
}
.tlf-11 {
width: 100%;
min-height: 100svh;
}
/* Older WebKit still wants the prefixed backface property. */
.tlf-11 form {
-webkit-backface-visibility: hidden;
}@import "tailwindcss";
@theme {
--color-tlf11-stage: #f5f2ef;
--color-tlf11-stage: oklch(0.96 0.008 60);
--color-tlf11-edge: #eadfd6;
--color-tlf11-edge: oklch(0.91 0.015 60);
--color-tlf11-fieldedge: #e0d3c8;
--color-tlf11-fieldedge: oklch(0.87 0.02 60);
--color-tlf11-field: #fdfbf9;
--color-tlf11-field: oklch(0.99 0.004 60);
--color-tlf11-ink: #2a1c12;
--color-tlf11-ink: oklch(0.25 0.03 50);
--color-tlf11-mut: #776154;
--color-tlf11-mut: oklch(0.52 0.03 50);
--color-tlf11-ph: #9a8577;
--color-tlf11-ph: oklch(0.63 0.03 50);
--color-tlf11-acc: #b1452a;
--color-tlf11-acc: oklch(0.53 0.17 30);
--color-tlf11-halo: #e9bdb0;
--color-tlf11-halo: oklch(0.53 0.17 30 / 0.16);
--color-tlf11-ring: #d9927f;
--color-tlf11-ring: oklch(0.53 0.17 30 / 0.5);
--font-tlf11-sans: 'Epilogue', system-ui, sans-serif;
}
.tlf-11 {
width: 100%;
min-height: 100svh;
}
/* Older WebKit still wants the prefixed backface property. */
.tlf-11 form {
-webkit-backface-visibility: hidden;
}<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=Epilogue:wght@400;500;600;700&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=Epilogue:wght@400;500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- This is the port that got shortest. v4 added
transform-3d,backface-hidden,rotate-y-*andperspective-*, so a demo that in v3 would have been four arbitrary properties is now four ordinary utilities. peer-checked:rotate-y-180replaces.flip:checked ~ .card{transform:rotateY(180deg)}, and the difference is that you can now see, from the card's own class list, that it flips and what flips it.motion-reduce:duration-0rather thanmotion-reduce:transition-none: the flip still happens (the back face must end up visible), it just happens instantly — the correct reduced-motion behaviour for a state change that is also a layout change.- UI change from the CSS original: Epilogue replaces the system stack, both flip links became 44px targets, fields went 46px → 48px, the muted note darkened from
#8a7565tooklch(0.52 0.03 50), and the terracotta accent deepened to0.53so white button text clears 4.5:1.
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 3D Flip Login Card with Password Reset Back Face
Source: https://codefronts.com/components/tailwind-css-login-forms/tailwind-3d-flip-login-card-password-reset/
Forgot Password lives on the back of the login card: tick a hidden checkbox and the whole card rotates in 3D to reveal the recovery form — no redirect, no bleed-through. v4 makes this port unusually clean, because rotate-y-180, backface-hidden, transform-3d and perspective-[1400px] are all real utilities now.
## HTML
```html
<section class="tlf-11 w-full min-h-svh grid place-items-center bg-tlf11-stage font-tlf11-sans p-6">
<div class="relative w-[min(380px,100%)] perspective-[1400px]">
<input type="checkbox" id="tlf-11-flip" aria-label="Show password reset form" class="peer sr-only">
<div class="relative w-full min-h-[420px] transform-3d transition-transform duration-700 ease-[cubic-bezier(0.4,0,0.2,1)] peer-checked:rotate-y-180 peer-focus-visible:outline-3 peer-focus-visible:outline-offset-[6px] peer-focus-visible:outline-tlf11-ring peer-focus-visible:rounded-[18px] motion-reduce:duration-0">
<form novalidate class="absolute inset-0 backface-hidden flex flex-col gap-3 p-8 bg-white border border-tlf11-edge rounded-[18px] shadow-[0_24px_56px_-38px_oklch(0.35_0.06_50/0.5)]">
<h2 class="mb-1 text-[23px] font-bold text-tlf11-ink">Sign in</h2>
<input type="email" placeholder="Email" autocomplete="email" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<input type="password" placeholder="Password" autocomplete="current-password" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<button type="submit" class="h-12 rounded-xl border-0 cursor-pointer bg-tlf11-acc text-white text-[15px] font-semibold transition-[filter,scale] duration-150 hover:brightness-110 active:scale-[0.985] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tlf11-ring motion-reduce:transition-none motion-reduce:active:scale-100">Log in</button>
<label for="tlf-11-flip" class="grid place-items-center self-center min-h-11 px-2 text-[13px] font-semibold text-tlf11-acc cursor-pointer hover:underline">Forgot password?</label>
</form>
<form novalidate class="absolute inset-0 backface-hidden rotate-y-180 flex flex-col gap-3 p-8 bg-white border border-tlf11-edge rounded-[18px] shadow-[0_24px_56px_-38px_oklch(0.35_0.06_50/0.5)]">
<h2 class="text-[23px] font-bold text-tlf11-ink">Reset password</h2>
<p class="-mt-1.5 mb-1 text-[13.5px]/[1.5] text-tlf11-mut">Enter your email and we’ll send a reset link.</p>
<input type="email" placeholder="Email" autocomplete="email" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<button type="submit" class="h-12 rounded-xl border-0 cursor-pointer bg-tlf11-acc text-white text-[15px] font-semibold transition-[filter,scale] duration-150 hover:brightness-110 active:scale-[0.985] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tlf11-ring motion-reduce:transition-none motion-reduce:active:scale-100">Send link</button>
<label for="tlf-11-flip" class="grid place-items-center self-center min-h-11 px-2 text-[13px] font-semibold text-tlf11-acc cursor-pointer hover:underline">← Back to sign in</label>
</form>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tlf11-stage: #f5f2ef;
--color-tlf11-stage: oklch(0.96 0.008 60);
--color-tlf11-edge: #eadfd6;
--color-tlf11-edge: oklch(0.91 0.015 60);
--color-tlf11-fieldedge: #e0d3c8;
--color-tlf11-fieldedge: oklch(0.87 0.02 60);
--color-tlf11-field: #fdfbf9;
--color-tlf11-field: oklch(0.99 0.004 60);
--color-tlf11-ink: #2a1c12;
--color-tlf11-ink: oklch(0.25 0.03 50);
--color-tlf11-mut: #776154;
--color-tlf11-mut: oklch(0.52 0.03 50);
--color-tlf11-ph: #9a8577;
--color-tlf11-ph: oklch(0.63 0.03 50);
--color-tlf11-acc: #b1452a;
--color-tlf11-acc: oklch(0.53 0.17 30);
--color-tlf11-halo: #e9bdb0;
--color-tlf11-halo: oklch(0.53 0.17 30 / 0.16);
--color-tlf11-ring: #d9927f;
--color-tlf11-ring: oklch(0.53 0.17 30 / 0.5);
--font-tlf11-sans: 'Epilogue', system-ui, sans-serif;
}
.tlf-11 {
width: 100%;
min-height: 100svh;
}
/* Older WebKit still wants the prefixed backface property. */
.tlf-11 form {
-webkit-backface-visibility: hidden;
}
```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 3D Flip Login Card with Password Reset Back Face
Source: https://codefronts.com/components/tailwind-css-login-forms/tailwind-3d-flip-login-card-password-reset/
Forgot Password lives on the back of the login card: tick a hidden checkbox and the whole card rotates in 3D to reveal the recovery form — no redirect, no bleed-through. v4 makes this port unusually clean, because rotate-y-180, backface-hidden, transform-3d and perspective-[1400px] are all real utilities now.
## HTML
```html
<section class="tlf-11 w-full min-h-svh grid place-items-center bg-tlf11-stage font-tlf11-sans p-6">
<div class="relative w-[min(380px,100%)] perspective-[1400px]">
<input type="checkbox" id="tlf-11-flip" aria-label="Show password reset form" class="peer sr-only">
<div class="relative w-full min-h-[420px] transform-3d transition-transform duration-700 ease-[cubic-bezier(0.4,0,0.2,1)] peer-checked:rotate-y-180 peer-focus-visible:outline-3 peer-focus-visible:outline-offset-[6px] peer-focus-visible:outline-tlf11-ring peer-focus-visible:rounded-[18px] motion-reduce:duration-0">
<form novalidate class="absolute inset-0 backface-hidden flex flex-col gap-3 p-8 bg-white border border-tlf11-edge rounded-[18px] shadow-[0_24px_56px_-38px_oklch(0.35_0.06_50/0.5)]">
<h2 class="mb-1 text-[23px] font-bold text-tlf11-ink">Sign in</h2>
<input type="email" placeholder="Email" autocomplete="email" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<input type="password" placeholder="Password" autocomplete="current-password" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<button type="submit" class="h-12 rounded-xl border-0 cursor-pointer bg-tlf11-acc text-white text-[15px] font-semibold transition-[filter,scale] duration-150 hover:brightness-110 active:scale-[0.985] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tlf11-ring motion-reduce:transition-none motion-reduce:active:scale-100">Log in</button>
<label for="tlf-11-flip" class="grid place-items-center self-center min-h-11 px-2 text-[13px] font-semibold text-tlf11-acc cursor-pointer hover:underline">Forgot password?</label>
</form>
<form novalidate class="absolute inset-0 backface-hidden rotate-y-180 flex flex-col gap-3 p-8 bg-white border border-tlf11-edge rounded-[18px] shadow-[0_24px_56px_-38px_oklch(0.35_0.06_50/0.5)]">
<h2 class="text-[23px] font-bold text-tlf11-ink">Reset password</h2>
<p class="-mt-1.5 mb-1 text-[13.5px]/[1.5] text-tlf11-mut">Enter your email and we’ll send a reset link.</p>
<input type="email" placeholder="Email" autocomplete="email" required class="h-12 px-3.5 rounded-xl text-[14.5px] text-tlf11-ink bg-tlf11-field border-[1.5px] border-tlf11-fieldedge transition-[border-color,box-shadow] duration-150 placeholder:text-tlf11-ph focus-visible:outline-none focus-visible:border-tlf11-acc focus-visible:ring-4 focus-visible:ring-tlf11-halo">
<button type="submit" class="h-12 rounded-xl border-0 cursor-pointer bg-tlf11-acc text-white text-[15px] font-semibold transition-[filter,scale] duration-150 hover:brightness-110 active:scale-[0.985] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tlf11-ring motion-reduce:transition-none motion-reduce:active:scale-100">Send link</button>
<label for="tlf-11-flip" class="grid place-items-center self-center min-h-11 px-2 text-[13px] font-semibold text-tlf11-acc cursor-pointer hover:underline">← Back to sign in</label>
</form>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tlf11-stage: #f5f2ef;
--color-tlf11-stage: oklch(0.96 0.008 60);
--color-tlf11-edge: #eadfd6;
--color-tlf11-edge: oklch(0.91 0.015 60);
--color-tlf11-fieldedge: #e0d3c8;
--color-tlf11-fieldedge: oklch(0.87 0.02 60);
--color-tlf11-field: #fdfbf9;
--color-tlf11-field: oklch(0.99 0.004 60);
--color-tlf11-ink: #2a1c12;
--color-tlf11-ink: oklch(0.25 0.03 50);
--color-tlf11-mut: #776154;
--color-tlf11-mut: oklch(0.52 0.03 50);
--color-tlf11-ph: #9a8577;
--color-tlf11-ph: oklch(0.63 0.03 50);
--color-tlf11-acc: #b1452a;
--color-tlf11-acc: oklch(0.53 0.17 30);
--color-tlf11-halo: #e9bdb0;
--color-tlf11-halo: oklch(0.53 0.17 30 / 0.16);
--color-tlf11-ring: #d9927f;
--color-tlf11-ring: oklch(0.53 0.17 30 / 0.5);
--font-tlf11-sans: 'Epilogue', system-ui, sans-serif;
}
.tlf-11 {
width: 100%;
min-height: 100svh;
}
/* Older WebKit still wants the prefixed backface property. */
.tlf-11 form {
-webkit-backface-visibility: hidden;
}
```How this works
Two faces, both hiding their backs. backface-hidden on both the front and the back is the one non-negotiable line — omit it on either and the mirrored text of the other face shows through mid-rotation. The back face sits pre-rotated 180° so that when the card turns, it arrives facing the viewer.
Perspective belongs to the stage. perspective-[1400px] on the wrapper, not on the card: applied to the rotating element itself, the vanishing point travels with it and the depth reads wrong.
The toggle is a checkbox and the triggers are labels. “Forgot password?” on the front and “Back to sign in” on the back are both <label for>s of the same peer sr-only input, so the flip is keyboard-operable and peer-focus-visible: rings the card.
Make it yours
- Flip axis:
rotate-y-180→rotate-x-180for a vertical turn. - Depth: the
perspective-[1400px]value — lower is more dramatic. - Accent:
--color-tlf11-accdrives buttons, links and both focus rings. - Card height:
min-h-[420px]must fit the taller of the two faces, since both are absolutely positioned.
Gotchas — read before shipping
backface-hiddenon BOTH faces. Half the flip-card bugs on the internet are this line missing from one of them.perspective-*on the parent, never the rotating element.- Both faces are
absolute inset-0, so the stage needs an explicitmin-h-*— absolutely positioned children contribute nothing to their parent's height, and without it the card collapses to zero.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
preserve-3d and backface-visibility are universally supported (the stylesheet ships the -webkit- backface prefix for older WebKit); the floor is Tailwind v4's generated sheet.