30 CSS Login Forms11 / 30
Card Flip Reset
The Forgot Password lives on the back of the login card. Click the reset link and the whole card rotates in 3D to reveal the recovery form — no page redirect, no glitchy bleed-through.
Published Updated
The code
<section class="lf-11">
<div class="lf-11__stage">
<input type="checkbox" class="lf-11__flip" id="lf-11-flip" aria-label="Show password reset form">
<div class="lf-11__card">
<form class="lf-11__face lf-11__face--front" novalidate>
<h2 class="lf-11__h">Sign in</h2>
<input type="email" placeholder="Email" autocomplete="email" required>
<input type="password" placeholder="Password" autocomplete="current-password" required>
<button type="submit">Log in</button>
<label class="lf-11__link" for="lf-11-flip">Forgot password?</label>
</form>
<form class="lf-11__face lf-11__face--back" novalidate>
<h2 class="lf-11__h">Reset password</h2>
<p class="lf-11__note">Enter your email and we'll send a reset link.</p>
<input type="email" placeholder="Email" autocomplete="email" required>
<button type="submit">Send link</button>
<label class="lf-11__link" for="lf-11-flip">← Back to sign in</label>
</form>
</div>
</div>
</section><section class="lf-11">
<div class="lf-11__stage">
<input type="checkbox" class="lf-11__flip" id="lf-11-flip" aria-label="Show password reset form">
<div class="lf-11__card">
<form class="lf-11__face lf-11__face--front" novalidate>
<h2 class="lf-11__h">Sign in</h2>
<input type="email" placeholder="Email" autocomplete="email" required>
<input type="password" placeholder="Password" autocomplete="current-password" required>
<button type="submit">Log in</button>
<label class="lf-11__link" for="lf-11-flip">Forgot password?</label>
</form>
<form class="lf-11__face lf-11__face--back" novalidate>
<h2 class="lf-11__h">Reset password</h2>
<p class="lf-11__note">Enter your email and we'll send a reset link.</p>
<input type="email" placeholder="Email" autocomplete="email" required>
<button type="submit">Send link</button>
<label class="lf-11__link" for="lf-11-flip">← Back to sign in</label>
</form>
</div>
</div>
</section>.lf-11,
.lf-11 *,
.lf-11 *::before,
.lf-11 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.lf-11 {
--accent: oklch(0.55 0.18 25);
--radius: 12px;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
background: #f5f2ef;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.lf-11__stage {
width: min(360px,100%);
perspective: 1400px;
}
.lf-11__flip {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
.lf-11__card {
position: relative;
width: 100%;
min-height: 400px;
transform-style: preserve-3d;
transition: transform .7s cubic-bezier(.4,0,.2,1);
}
.lf-11__flip:checked ~ .lf-11__card {
transform: rotateY(180deg);
}
.lf-11__flip:focus-visible ~ .lf-11__card {
outline: 3px solid oklch(0.55 0.18 25/.5);
outline-offset: 6px;
border-radius: 20px;
}
.lf-11__face {
position: absolute;
inset: 0;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
background: #fff;
border: 1px solid #eadfd6;
border-radius: 18px;
padding: 36px 32px;
display: flex;
flex-direction: column;
gap: 13px;
box-shadow: 0 24px 56px -38px rgba(60,30,10,.5);
}
.lf-11__face--back {
transform: rotateY(180deg);
}
.lf-11__h {
font-size: 23px;
font-weight: 700;
color: #2a1c12;
margin-bottom: 4px;
}
.lf-11__note {
font-size: 13.5px;
line-height: 1.5;
color: #8a7565;
margin-top: -6px;
margin-bottom: 4px;
}
.lf-11__face input {
height: 46px;
border: 1.5px solid #e0d3c8;
border-radius: var(--radius);
padding: 0 14px;
font-size: 14.5px;
color: #2a1c12;
background: #fdfbf9;
transition: border-color .18s,box-shadow .18s;
}
.lf-11__face input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px oklch(0.55 0.18 25/.16);
}
.lf-11__face button {
height: 46px;
margin-top: 2px;
border: 0;
border-radius: var(--radius);
cursor: pointer;
background: var(--accent);
color: #fff;
font-size: 15px;
font-weight: 600;
transition: filter .18s,transform .12s;
}
.lf-11__face button:hover {
filter: brightness(1.06);
}
.lf-11__face button:active {
transform: scale(.985);
}
.lf-11__face button:focus-visible {
outline: 3px solid oklch(0.55 0.18 25/.5);
outline-offset: 2px;
}
.lf-11__link {
align-self: center;
font-size: 13px;
color: var(--accent);
font-weight: 600;
cursor: pointer;
text-decoration: none;
}
.lf-11__link:hover {
text-decoration: underline;
}
@media (prefers-reduced-motion: reduce) {
.lf-11__card {
transition: none;
}
}.lf-11,
.lf-11 *,
.lf-11 *::before,
.lf-11 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.lf-11 {
--accent: oklch(0.55 0.18 25);
--radius: 12px;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
background: #f5f2ef;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.lf-11__stage {
width: min(360px,100%);
perspective: 1400px;
}
.lf-11__flip {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
.lf-11__card {
position: relative;
width: 100%;
min-height: 400px;
transform-style: preserve-3d;
transition: transform .7s cubic-bezier(.4,0,.2,1);
}
.lf-11__flip:checked ~ .lf-11__card {
transform: rotateY(180deg);
}
.lf-11__flip:focus-visible ~ .lf-11__card {
outline: 3px solid oklch(0.55 0.18 25/.5);
outline-offset: 6px;
border-radius: 20px;
}
.lf-11__face {
position: absolute;
inset: 0;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
background: #fff;
border: 1px solid #eadfd6;
border-radius: 18px;
padding: 36px 32px;
display: flex;
flex-direction: column;
gap: 13px;
box-shadow: 0 24px 56px -38px rgba(60,30,10,.5);
}
.lf-11__face--back {
transform: rotateY(180deg);
}
.lf-11__h {
font-size: 23px;
font-weight: 700;
color: #2a1c12;
margin-bottom: 4px;
}
.lf-11__note {
font-size: 13.5px;
line-height: 1.5;
color: #8a7565;
margin-top: -6px;
margin-bottom: 4px;
}
.lf-11__face input {
height: 46px;
border: 1.5px solid #e0d3c8;
border-radius: var(--radius);
padding: 0 14px;
font-size: 14.5px;
color: #2a1c12;
background: #fdfbf9;
transition: border-color .18s,box-shadow .18s;
}
.lf-11__face input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px oklch(0.55 0.18 25/.16);
}
.lf-11__face button {
height: 46px;
margin-top: 2px;
border: 0;
border-radius: var(--radius);
cursor: pointer;
background: var(--accent);
color: #fff;
font-size: 15px;
font-weight: 600;
transition: filter .18s,transform .12s;
}
.lf-11__face button:hover {
filter: brightness(1.06);
}
.lf-11__face button:active {
transform: scale(.985);
}
.lf-11__face button:focus-visible {
outline: 3px solid oklch(0.55 0.18 25/.5);
outline-offset: 2px;
}
.lf-11__link {
align-self: center;
font-size: 13px;
color: var(--accent);
font-weight: 600;
cursor: pointer;
text-decoration: none;
}
.lf-11__link:hover {
text-decoration: underline;
}
@media (prefers-reduced-motion: reduce) {
.lf-11__card {
transition: none;
}
}/* No JavaScript — a preserve-3d card rotates via a focusable checkbox; both faces hide their backface. */
/* No JavaScript — a preserve-3d card rotates via a focusable checkbox; both faces hide their backface. */Here's a working CSS Login Form 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: Card Flip Reset
Source: https://codefronts.com/components/css-login-forms/card-flip-reset/
The Forgot Password lives on the back of the login card. Click the reset link and the whole card rotates in 3D to reveal the recovery form — no page redirect, no glitchy bleed-through.
## HTML
```html
<section class="lf-11">
<div class="lf-11__stage">
<input type="checkbox" class="lf-11__flip" id="lf-11-flip" aria-label="Show password reset form">
<div class="lf-11__card">
<form class="lf-11__face lf-11__face--front" novalidate>
<h2 class="lf-11__h">Sign in</h2>
<input type="email" placeholder="Email" autocomplete="email" required>
<input type="password" placeholder="Password" autocomplete="current-password" required>
<button type="submit">Log in</button>
<label class="lf-11__link" for="lf-11-flip">Forgot password?</label>
</form>
<form class="lf-11__face lf-11__face--back" novalidate>
<h2 class="lf-11__h">Reset password</h2>
<p class="lf-11__note">Enter your email and we'll send a reset link.</p>
<input type="email" placeholder="Email" autocomplete="email" required>
<button type="submit">Send link</button>
<label class="lf-11__link" for="lf-11-flip">← Back to sign in</label>
</form>
</div>
</div>
</section>
```
## CSS
```css
.lf-11,
.lf-11 *,
.lf-11 *::before,
.lf-11 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.lf-11 {
--accent: oklch(0.55 0.18 25);
--radius: 12px;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
background: #f5f2ef;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.lf-11__stage {
width: min(360px,100%);
perspective: 1400px;
}
.lf-11__flip {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
.lf-11__card {
position: relative;
width: 100%;
min-height: 400px;
transform-style: preserve-3d;
transition: transform .7s cubic-bezier(.4,0,.2,1);
}
.lf-11__flip:checked ~ .lf-11__card {
transform: rotateY(180deg);
}
.lf-11__flip:focus-visible ~ .lf-11__card {
outline: 3px solid oklch(0.55 0.18 25/.5);
outline-offset: 6px;
border-radius: 20px;
}
.lf-11__face {
position: absolute;
inset: 0;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
background: #fff;
border: 1px solid #eadfd6;
border-radius: 18px;
padding: 36px 32px;
display: flex;
flex-direction: column;
gap: 13px;
box-shadow: 0 24px 56px -38px rgba(60,30,10,.5);
}
.lf-11__face--back {
transform: rotateY(180deg);
}
.lf-11__h {
font-size: 23px;
font-weight: 700;
color: #2a1c12;
margin-bottom: 4px;
}
.lf-11__note {
font-size: 13.5px;
line-height: 1.5;
color: #8a7565;
margin-top: -6px;
margin-bottom: 4px;
}
.lf-11__face input {
height: 46px;
border: 1.5px solid #e0d3c8;
border-radius: var(--radius);
padding: 0 14px;
font-size: 14.5px;
color: #2a1c12;
background: #fdfbf9;
transition: border-color .18s,box-shadow .18s;
}
.lf-11__face input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px oklch(0.55 0.18 25/.16);
}
.lf-11__face button {
height: 46px;
margin-top: 2px;
border: 0;
border-radius: var(--radius);
cursor: pointer;
background: var(--accent);
color: #fff;
font-size: 15px;
font-weight: 600;
transition: filter .18s,transform .12s;
}
.lf-11__face button:hover {
filter: brightness(1.06);
}
.lf-11__face button:active {
transform: scale(.985);
}
.lf-11__face button:focus-visible {
outline: 3px solid oklch(0.55 0.18 25/.5);
outline-offset: 2px;
}
.lf-11__link {
align-self: center;
font-size: 13px;
color: var(--accent);
font-weight: 600;
cursor: pointer;
text-decoration: none;
}
.lf-11__link:hover {
text-decoration: underline;
}
@media (prefers-reduced-motion: reduce) {
.lf-11__card {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — a preserve-3d card rotates via a focusable checkbox; both faces hide their backface. */
```Here's a working CSS Login Form 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: Card Flip Reset
Source: https://codefronts.com/components/css-login-forms/card-flip-reset/
The Forgot Password lives on the back of the login card. Click the reset link and the whole card rotates in 3D to reveal the recovery form — no page redirect, no glitchy bleed-through.
## HTML
```html
<section class="lf-11">
<div class="lf-11__stage">
<input type="checkbox" class="lf-11__flip" id="lf-11-flip" aria-label="Show password reset form">
<div class="lf-11__card">
<form class="lf-11__face lf-11__face--front" novalidate>
<h2 class="lf-11__h">Sign in</h2>
<input type="email" placeholder="Email" autocomplete="email" required>
<input type="password" placeholder="Password" autocomplete="current-password" required>
<button type="submit">Log in</button>
<label class="lf-11__link" for="lf-11-flip">Forgot password?</label>
</form>
<form class="lf-11__face lf-11__face--back" novalidate>
<h2 class="lf-11__h">Reset password</h2>
<p class="lf-11__note">Enter your email and we'll send a reset link.</p>
<input type="email" placeholder="Email" autocomplete="email" required>
<button type="submit">Send link</button>
<label class="lf-11__link" for="lf-11-flip">← Back to sign in</label>
</form>
</div>
</div>
</section>
```
## CSS
```css
.lf-11,
.lf-11 *,
.lf-11 *::before,
.lf-11 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.lf-11 {
--accent: oklch(0.55 0.18 25);
--radius: 12px;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
background: #f5f2ef;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.lf-11__stage {
width: min(360px,100%);
perspective: 1400px;
}
.lf-11__flip {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
.lf-11__card {
position: relative;
width: 100%;
min-height: 400px;
transform-style: preserve-3d;
transition: transform .7s cubic-bezier(.4,0,.2,1);
}
.lf-11__flip:checked ~ .lf-11__card {
transform: rotateY(180deg);
}
.lf-11__flip:focus-visible ~ .lf-11__card {
outline: 3px solid oklch(0.55 0.18 25/.5);
outline-offset: 6px;
border-radius: 20px;
}
.lf-11__face {
position: absolute;
inset: 0;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
background: #fff;
border: 1px solid #eadfd6;
border-radius: 18px;
padding: 36px 32px;
display: flex;
flex-direction: column;
gap: 13px;
box-shadow: 0 24px 56px -38px rgba(60,30,10,.5);
}
.lf-11__face--back {
transform: rotateY(180deg);
}
.lf-11__h {
font-size: 23px;
font-weight: 700;
color: #2a1c12;
margin-bottom: 4px;
}
.lf-11__note {
font-size: 13.5px;
line-height: 1.5;
color: #8a7565;
margin-top: -6px;
margin-bottom: 4px;
}
.lf-11__face input {
height: 46px;
border: 1.5px solid #e0d3c8;
border-radius: var(--radius);
padding: 0 14px;
font-size: 14.5px;
color: #2a1c12;
background: #fdfbf9;
transition: border-color .18s,box-shadow .18s;
}
.lf-11__face input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px oklch(0.55 0.18 25/.16);
}
.lf-11__face button {
height: 46px;
margin-top: 2px;
border: 0;
border-radius: var(--radius);
cursor: pointer;
background: var(--accent);
color: #fff;
font-size: 15px;
font-weight: 600;
transition: filter .18s,transform .12s;
}
.lf-11__face button:hover {
filter: brightness(1.06);
}
.lf-11__face button:active {
transform: scale(.985);
}
.lf-11__face button:focus-visible {
outline: 3px solid oklch(0.55 0.18 25/.5);
outline-offset: 2px;
}
.lf-11__link {
align-self: center;
font-size: 13px;
color: var(--accent);
font-weight: 600;
cursor: pointer;
text-decoration: none;
}
.lf-11__link:hover {
text-decoration: underline;
}
@media (prefers-reduced-motion: reduce) {
.lf-11__card {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — a preserve-3d card rotates via a focusable checkbox; both faces hide their backface. */
```How this works
The card is a transform-style: preserve-3d container with two absolutely-stacked faces, each set to backface-visibility: hidden. The back face is pre-rotated 180°. A hidden focusable checkbox holds the flipped state and rotates the inner card rotateY(180deg).
Because both faces hide their backface, content never bleeds through during the rotation — the clean spec-correct result across Chromium and WebKit. The flip buttons are <label>s for the checkbox, so it's keyboard-operable.
Only transform animates, so the flip is GPU-composited; a perspective on the stage gives it real depth.
Make it yours
- Flip axis: switch
rotateYtorotateXfor a vertical flip. - Tune depth with the stage
perspectivevalue. - Recolour from
--accent. - Add a third state by nesting another preserve-3d layer if you need a security-questions face.
Gotchas — read before shipping
- Set
backface-visibility:hiddenon BOTH faces or the reversed text shows through mid-flip. - Put
perspectiveon the parent stage, not the rotating element, for correct depth. - Keep the flip toggle a focusable control (label + sr-only checkbox), not a click-only div.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 15.4+ | 113+ | 111+ |
Floor set by oklch() as this demo is written. The core technique itself goes back further — Chrome 36+.
preserve-3d and backface-visibility are universally supported across Chromium and WebKit.