3D Flip Login & Signup Form
A modern glassmorphism authentication form with a smooth 3D flip transition between sign in and account creation, password visibility controls and responsive styling.
Sign in
Enter your details to continue.
New here?
<section class="cr-authflip" aria-label="Account access">
<div class="cr-authflip__glow cr-authflip__glow--one" aria-hidden="true"></div>
<div class="cr-authflip__glow cr-authflip__glow--two" aria-hidden="true"></div>
<div class="cr-authflip__scene">
<div class="cr-authflip__card">
<div class="cr-authflip__face cr-authflip__face--login">
<div class="cr-authflip__brand" aria-hidden="true">
<span class="cr-authflip__brand-mark"></span>
</div>
<div class="cr-authflip__heading">
<span class="cr-authflip__eyebrow">Welcome back</span>
<h2>Sign in</h2>
<p>Enter your details to continue.</p>
</div>
<form class="cr-authflip__form">
<label class="cr-authflip__field">
<span>Email address</span>
<input
type="email"
name="email"
placeholder="name@example.com"
autocomplete="email"
required
>
</label>
<label class="cr-authflip__field">
<span>Password</span>
<span class="cr-authflip__password">
<input
type="password"
name="password"
placeholder="Enter your password"
autocomplete="current-password"
required
>
<button
class="cr-authflip__password-toggle"
type="button"
aria-label="Show password"
aria-pressed="false"
>
<span aria-hidden="true">◉</span>
</button>
</span>
</label>
<div class="cr-authflip__options">
<label class="cr-authflip__remember">
<input type="checkbox" name="remember">
<span>Remember me</span>
</label>
<a href="#" class="cr-authflip__link">Forgot password?</a>
</div>
<button class="cr-authflip__primary" type="submit">
<span>Sign in</span>
<span aria-hidden="true">→</span>
</button>
</form>
<div class="cr-authflip__divider">
<span>or continue with</span>
</div>
<div class="cr-authflip__socials">
<button type="button" class="cr-authflip__social">
<span aria-hidden="true">G</span>
<span>Google</span>
</button>
<button type="button" class="cr-authflip__social">
<span aria-hidden="true">A</span>
<span>Apple</span>
</button>
</div>
<p class="cr-authflip__switch-text">
New here?
<button
class="cr-authflip__switch"
type="button"
data-cr-authflip-target="signup"
>
Create an account
</button>
</p>
</div>
<div
class="cr-authflip__face cr-authflip__face--signup"
aria-hidden="true"
>
<div class="cr-authflip__brand" aria-hidden="true">
<span class="cr-authflip__brand-mark"></span>
</div>
<div class="cr-authflip__heading">
<span class="cr-authflip__eyebrow">Start something new</span>
<h2>Create account</h2>
<p>Set up your account in a few seconds.</p>
</div>
<form class="cr-authflip__form">
<label class="cr-authflip__field">
<span>Full name</span>
<input
type="text"
name="name"
placeholder="Your name"
autocomplete="name"
required
>
</label>
<label class="cr-authflip__field">
<span>Email address</span>
<input
type="email"
name="email"
placeholder="name@example.com"
autocomplete="email"
required
>
</label>
<label class="cr-authflip__field">
<span>Password</span>
<span class="cr-authflip__password">
<input
type="password"
name="password"
placeholder="Create a password"
autocomplete="new-password"
required
>
<button
class="cr-authflip__password-toggle"
type="button"
aria-label="Show password"
aria-pressed="false"
>
<span aria-hidden="true">◉</span>
</button>
</span>
</label>
<label class="cr-authflip__terms">
<input type="checkbox" name="terms" required>
<span>
I agree to the
<a href="#" class="cr-authflip__link">terms and conditions</a>
</span>
</label>
<button class="cr-authflip__primary" type="submit">
<span>Create account</span>
<span aria-hidden="true">→</span>
</button>
</form>
<p class="cr-authflip__switch-text">
Already have an account?
<button
class="cr-authflip__switch"
type="button"
data-cr-authflip-target="login"
>
Sign in
</button>
</p>
</div>
</div>
</div>
</section>
.cr-authflip {
--cr-af-bg: #070912;
--cr-af-panel: rgba(14, 17, 32, 0.78);
--cr-af-border: rgba(255, 255, 255, 0.11);
--cr-af-text: #f7f8ff;
--cr-af-muted: #9298ad;
--cr-af-accent: #65e8ff;
--cr-af-accent-2: #8c67ff;
position: relative;
isolation: isolate;
display: grid;
place-items: center;
width: 100%;
min-height: 720px;
padding: 48px 20px;
overflow: hidden;
border-radius: 28px;
background:
radial-gradient(
circle at 18% 20%,
rgba(101, 232, 255, 0.12),
transparent 30%
),
radial-gradient(
circle at 82% 75%,
rgba(140, 103, 255, 0.16),
transparent 32%
),
linear-gradient(145deg, #05060b 0%, #090b16 50%, #060711 100%);
color: var(--cr-af-text);
font-family:
Inter,
ui-sans-serif,
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
sans-serif;
}
.cr-authflip *,
.cr-authflip *::before,
.cr-authflip *::after {
box-sizing: border-box;
}
.cr-authflip__glow {
position: absolute;
z-index: -1;
width: 340px;
aspect-ratio: 1;
border-radius: 50%;
filter: blur(25px);
pointer-events: none;
}
.cr-authflip__glow--one {
top: -120px;
left: -90px;
background: rgba(70, 222, 255, 0.1);
}
.cr-authflip__glow--two {
right: -110px;
bottom: -140px;
background: rgba(126, 82, 255, 0.13);
}
.cr-authflip__scene {
position: relative;
width: min(100%, 430px);
perspective: 1500px;
}
.cr-authflip__card {
position: relative;
width: 100%;
min-height: 620px;
transform-style: preserve-3d;
transition:
transform 0.82s cubic-bezier(0.68, -0.2, 0.2, 1.18),
filter 0.4s ease;
will-change: transform;
}
.cr-authflip__card.is-signup {
transform: rotateY(180deg);
}
.cr-authflip__face {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
width: 100%;
padding: 34px;
overflow: hidden;
border: 1px solid var(--cr-af-border);
border-radius: 28px;
background:
linear-gradient(
145deg,
rgba(255, 255, 255, 0.075),
rgba(255, 255, 255, 0.018)
),
var(--cr-af-panel);
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.48),
inset 0 1px 0 rgba(255, 255, 255, 0.08);
backdrop-filter: blur(22px);
-webkit-backdrop-filter: blur(22px);
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
.cr-authflip__face::before {
content: "";
position: absolute;
top: -100px;
left: 10%;
width: 80%;
height: 170px;
border-radius: 50%;
background: rgba(101, 232, 255, 0.12);
filter: blur(55px);
pointer-events: none;
}
.cr-authflip__face--signup {
transform: rotateY(180deg);
}
.cr-authflip__face--signup::before {
background: rgba(140, 103, 255, 0.15);
}
.cr-authflip__brand {
position: relative;
display: flex;
align-items: center;
width: fit-content;
height: 34px;
margin-bottom: 28px;
}
.cr-authflip__brand-mark {
position: relative;
display: block;
width: 27px;
height: 27px;
transform: rotate(45deg);
border: 1px solid rgba(255, 255, 255, 0.35);
border-radius: 8px;
background:
linear-gradient(
135deg,
rgba(101, 232, 255, 0.95),
rgba(140, 103, 255, 0.9)
);
box-shadow:
0 0 25px rgba(101, 232, 255, 0.22),
0 0 35px rgba(140, 103, 255, 0.15);
}
.cr-authflip__brand-mark::after {
content: "";
position: absolute;
inset: 6px;
border: 2px solid rgba(8, 10, 20, 0.75);
border-radius: 4px;
}
.cr-authflip__heading {
position: relative;
margin-bottom: 27px;
}
.cr-authflip__eyebrow {
display: inline-block;
margin-bottom: 8px;
color: var(--cr-af-accent);
font-size: 0.72rem;
font-weight: 700;
line-height: 1.3;
letter-spacing: 0.15em;
text-transform: uppercase;
}
.cr-authflip__face--signup .cr-authflip__eyebrow {
color: #ae98ff;
}
.cr-authflip__heading h2 {
margin: 0;
color: var(--cr-af-text);
font-size: clamp(2rem, 6vw, 2.65rem);
font-weight: 700;
line-height: 1.05;
letter-spacing: -0.045em;
}
.cr-authflip__heading p {
margin: 10px 0 0;
color: var(--cr-af-muted);
font-size: 0.92rem;
line-height: 1.6;
}
.cr-authflip__form {
display: grid;
gap: 17px;
}
.cr-authflip__field {
display: grid;
gap: 8px;
color: #c6cada;
font-size: 0.78rem;
font-weight: 600;
}
.cr-authflip__field > input,
.cr-authflip__password {
width: 100%;
}
.cr-authflip__field input {
min-width: 0;
height: 48px;
margin: 0;
padding: 0 15px;
outline: none;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
background: rgba(5, 7, 16, 0.65);
box-shadow: none;
color: var(--cr-af-text);
font: inherit;
font-size: 0.9rem;
transition:
border-color 0.25s ease,
background-color 0.25s ease,
box-shadow 0.25s ease;
}
.cr-authflip__field input::placeholder {
color: #646a7e;
opacity: 1;
}
.cr-authflip__field input:hover {
border-color: rgba(255, 255, 255, 0.18);
}
.cr-authflip__field input:focus {
border-color: rgba(101, 232, 255, 0.65);
background: rgba(7, 10, 21, 0.85);
box-shadow: 0 0 0 3px rgba(101, 232, 255, 0.09);
}
.cr-authflip__face--signup .cr-authflip__field input:focus {
border-color: rgba(174, 152, 255, 0.7);
box-shadow: 0 0 0 3px rgba(140, 103, 255, 0.11);
}
.cr-authflip__password {
position: relative;
display: block;
}
.cr-authflip__password input {
width: 100%;
padding-right: 50px;
}
.cr-authflip__password-toggle {
position: absolute;
top: 50%;
right: 8px;
display: grid;
place-items: center;
width: 34px;
height: 34px;
padding: 0;
transform: translateY(-50%);
border: 0;
border-radius: 9px;
background: transparent;
box-shadow: none;
color: #747b91;
font: inherit;
cursor: pointer;
transition:
color 0.2s ease,
background-color 0.2s ease;
}
.cr-authflip__password-toggle:hover,
.cr-authflip__password-toggle:focus-visible {
background: rgba(255, 255, 255, 0.06);
color: var(--cr-af-text);
}
.cr-authflip__options {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.cr-authflip__remember,
.cr-authflip__terms {
display: flex;
align-items: center;
gap: 8px;
color: var(--cr-af-muted);
font-size: 0.76rem;
line-height: 1.45;
cursor: pointer;
}
.cr-authflip__remember input,
.cr-authflip__terms input {
width: 15px;
height: 15px;
margin: 0;
accent-color: var(--cr-af-accent);
}
.cr-authflip__terms {
align-items: flex-start;
}
.cr-authflip__terms input {
flex: 0 0 auto;
margin-top: 2px;
}
.cr-authflip__link {
color: #b7bdcf;
font-size: 0.76rem;
font-weight: 600;
text-decoration: none;
transition: color 0.2s ease;
}
.cr-authflip__link:hover {
color: var(--cr-af-accent);
}
.cr-authflip__primary {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
width: 100%;
min-height: 49px;
margin: 2px 0 0;
padding: 0 20px;
overflow: hidden;
border: 0;
border-radius: 13px;
background: linear-gradient(
110deg,
var(--cr-af-accent),
#80baff 48%,
var(--cr-af-accent-2)
);
box-shadow:
0 10px 28px rgba(83, 190, 255, 0.17),
inset 0 1px 0 rgba(255, 255, 255, 0.45);
color: #080a13;
font: inherit;
font-size: 0.88rem;
font-weight: 750;
cursor: pointer;
transition:
transform 0.25s ease,
box-shadow 0.25s ease,
filter 0.25s ease;
}
.cr-authflip__primary:hover {
transform: translateY(-2px);
filter: brightness(1.06);
box-shadow:
0 14px 34px rgba(83, 190, 255, 0.24),
inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
.cr-authflip__primary:active {
transform: translateY(0);
}
.cr-authflip__primary span:last-child {
font-size: 1.15rem;
transition: transform 0.25s ease;
}
.cr-authflip__primary:hover span:last-child {
transform: translateX(3px);
}
.cr-authflip__divider {
display: flex;
align-items: center;
gap: 12px;
margin: 21px 0 16px;
color: #686f84;
font-size: 0.7rem;
white-space: nowrap;
}
.cr-authflip__divider::before,
.cr-authflip__divider::after {
content: "";
width: 100%;
height: 1px;
background: rgba(255, 255, 255, 0.08);
}
.cr-authflip__socials {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 11px;
}
.cr-authflip__social {
display: flex;
align-items: center;
justify-content: center;
gap: 9px;
min-height: 44px;
padding: 0 14px;
border: 1px solid rgba(255, 255, 255, 0.09);
border-radius: 11px;
background: rgba(255, 255, 255, 0.035);
box-shadow: none;
color: #d8dbe7;
font: inherit;
font-size: 0.78rem;
font-weight: 600;
cursor: pointer;
transition:
transform 0.22s ease,
border-color 0.22s ease,
background-color 0.22s ease;
}
.cr-authflip__social:hover {
transform: translateY(-2px);
border-color: rgba(255, 255, 255, 0.17);
background: rgba(255, 255, 255, 0.065);
}
.cr-authflip__social > span:first-child {
display: grid;
place-items: center;
width: 20px;
height: 20px;
border-radius: 6px;
background: rgba(255, 255, 255, 0.08);
color: #fff;
font-size: 0.68rem;
}
.cr-authflip__switch-text {
margin: auto 0 0;
padding-top: 22px;
color: var(--cr-af-muted);
font-size: 0.78rem;
line-height: 1.5;
text-align: center;
}
.cr-authflip__switch {
margin: 0;
padding: 3px;
border: 0;
background: transparent;
box-shadow: none;
color: var(--cr-af-accent);
font: inherit;
font-weight: 700;
cursor: pointer;
transition:
color 0.2s ease,
text-shadow 0.2s ease;
}
.cr-authflip__switch:hover {
color: #b5f5ff;
text-shadow: 0 0 14px rgba(101, 232, 255, 0.35);
}
.cr-authflip__face--signup .cr-authflip__switch {
color: #ae98ff;
}
.cr-authflip__face--signup .cr-authflip__switch:hover {
color: #c9bcff;
text-shadow: 0 0 14px rgba(140, 103, 255, 0.4);
}
.cr-authflip button:focus-visible,
.cr-authflip a:focus-visible,
.cr-authflip input:focus-visible {
outline: 2px solid rgba(101, 232, 255, 0.9);
outline-offset: 3px;
}
/* Registration side needs slightly more vertical room */
.cr-authflip__face--signup {
min-height: 620px;
}
/* Tablet */
@media (max-width: 700px) {
.cr-authflip {
min-height: 680px;
padding: 30px 16px;
border-radius: 22px;
}
.cr-authflip__scene {
width: min(100%, 410px);
perspective: 1200px;
}
.cr-authflip__card {
min-height: 610px;
}
.cr-authflip__face {
padding: 29px;
border-radius: 24px;
}
}
/* Mobile */
@media (max-width: 480px) {
.cr-authflip {
min-height: 650px;
padding: 20px 12px;
border-radius: 18px;
}
.cr-authflip__scene {
perspective: 950px;
}
.cr-authflip__card {
min-height: 600px;
}
.cr-authflip__face {
padding: 25px 20px;
border-radius: 21px;
}
.cr-authflip__brand {
margin-bottom: 23px;
}
.cr-authflip__heading {
margin-bottom: 23px;
}
.cr-authflip__heading h2 {
font-size: 2rem;
}
.cr-authflip__options {
align-items: flex-start;
gap: 10px;
}
.cr-authflip__socials {
gap: 8px;
}
.cr-authflip__social {
padding-inline: 10px;
}
}
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
.cr-authflip__card,
.cr-authflip__primary,
.cr-authflip__primary span,
.cr-authflip__social,
.cr-authflip__switch,
.cr-authflip__field input {
transition-duration: 0.01ms !important;
}
}
/* ===== Card size / crop fix ===== */
.cr-authflip {
min-height: 620px;
padding: 30px 20px;
}
.cr-authflip__scene {
width: min(100%, 390px);
}
.cr-authflip__card {
min-height: 570px;
}
.cr-authflip__face {
padding: 26px 30px;
}
.cr-authflip__brand {
margin-bottom: 20px;
}
.cr-authflip__heading {
margin-bottom: 20px;
}
.cr-authflip__heading h2 {
font-size: 2.25rem;
}
.cr-authflip__heading p {
margin-top: 7px;
}
.cr-authflip__form {
gap: 13px;
}
.cr-authflip__field {
gap: 6px;
}
.cr-authflip__field input {
height: 44px;
}
.cr-authflip__primary {
min-height: 45px;
}
.cr-authflip__divider {
margin: 16px 0 13px;
}
.cr-authflip__social {
min-height: 41px;
}
.cr-authflip__switch-text {
padding-top: 16px;
}
/* Signup side */
.cr-authflip__face--signup {
min-height: 570px;
}
/* Mobile */
@media (max-width: 480px) {
.cr-authflip {
min-height: 590px;
padding: 18px 12px;
}
.cr-authflip__scene {
width: min(100%, 360px);
}
.cr-authflip__card {
min-height: 555px;
}
.cr-authflip__face,
.cr-authflip__face--signup {
min-height: 555px;
padding: 23px 20px;
}
.cr-authflip__heading h2 {
font-size: 1.9rem;
}
}
(() => {
const initAuthFlip = (component) => {
if (component.dataset.crAuthflipReady === "true") return;
const card = component.querySelector(".cr-authflip__card");
const loginFace = component.querySelector(".cr-authflip__face--login");
const signupFace = component.querySelector(".cr-authflip__face--signup");
if (!card || !loginFace || !signupFace) return;
component.dataset.crAuthflipReady = "true";
let currentView = "login";
let isAnimating = false;
const getFocusableElements = (face) => {
return face.querySelectorAll(
'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
);
};
const setFaceAccessibility = (activeFace, inactiveFace) => {
activeFace.setAttribute("aria-hidden", "false");
inactiveFace.setAttribute("aria-hidden", "true");
getFocusableElements(activeFace).forEach((element) => {
if (element.dataset.crPreviousTabindex !== undefined) {
const previousValue = element.dataset.crPreviousTabindex;
if (previousValue === "") {
element.removeAttribute("tabindex");
} else {
element.setAttribute("tabindex", previousValue);
}
delete element.dataset.crPreviousTabindex;
}
});
getFocusableElements(inactiveFace).forEach((element) => {
if (element.dataset.crPreviousTabindex === undefined) {
element.dataset.crPreviousTabindex =
element.getAttribute("tabindex") || "";
}
element.setAttribute("tabindex", "-1");
});
};
const switchView = (target) => {
if (
isAnimating ||
target === currentView ||
!["login", "signup"].includes(target)
) {
return;
}
isAnimating = true;
currentView = target;
const showingSignup = target === "signup";
card.classList.toggle("is-signup", showingSignup);
if (showingSignup) {
setFaceAccessibility(signupFace, loginFace);
} else {
setFaceAccessibility(loginFace, signupFace);
}
window.setTimeout(() => {
const activeFace = showingSignup ? signupFace : loginFace;
const firstInput = activeFace.querySelector("input");
isAnimating = false;
if (
firstInput &&
window.matchMedia("(pointer: fine)").matches
) {
firstInput.focus({ preventScroll: true });
}
}, 850);
};
setFaceAccessibility(loginFace, signupFace);
component.addEventListener("click", (event) => {
const switchButton = event.target.closest(
".cr-authflip__switch[data-cr-authflip-target]"
);
if (switchButton && component.contains(switchButton)) {
switchView(switchButton.dataset.crAuthflipTarget);
return;
}
const passwordButton = event.target.closest(
".cr-authflip__password-toggle"
);
if (!passwordButton || !component.contains(passwordButton)) return;
const passwordWrapper = passwordButton.closest(
".cr-authflip__password"
);
const input = passwordWrapper?.querySelector("input");
if (!input) return;
const isCurrentlyHidden = input.type === "password";
input.type = isCurrentlyHidden ? "text" : "password";
passwordButton.setAttribute(
"aria-pressed",
String(isCurrentlyHidden)
);
passwordButton.setAttribute(
"aria-label",
isCurrentlyHidden ? "Hide password" : "Show password"
);
});
component.addEventListener("submit", (event) => {
const form = event.target.closest(".cr-authflip__form");
if (!form) return;
/*
* Demo behavior:
* prevents the CodeRipple Playground from reloading.
*
* Remove this preventDefault() when connecting the form
* to a real login/registration endpoint.
*/
event.preventDefault();
});
};
const initAll = (root = document) => {
root.querySelectorAll(".cr-authflip").forEach(initAuthFlip);
};
initAll();
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (!(node instanceof Element)) return;
if (node.matches(".cr-authflip")) {
initAuthFlip(node);
}
initAll(node);
});
});
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
})();
How This 3D Flip Login & Signup Form Works
The 3D Flip Login & Signup Form places two account forms on opposite sides of the same card. The login face contains email and password fields, a Remember me checkbox, a forgot-password link, and Google and Apple buttons. The signup face adds full name, email, password, and a required terms checkbox. Buttons at the bottom of each face let users move between the two views.
The flip effect comes from CSS 3D transforms. The .cr-authflip__scene element applies perspective: 1500px, while the card uses transform-style: preserve-3d. The signup face starts at rotateY(180deg), and both faces use backface-visibility: hidden. When JavaScript adds the is-signup class to the card, the complete card rotates by 180 degrees on the Y axis, bringing the signup side into view.
The rotation uses a 0.82s transition with a custom cubic-bezier timing function. This gives the switch more movement than a basic linear rotation. For background reading on the core technique, see the MDN CSS transform documentation.
Visually, the component uses a dark glass-style panel. Each face has a translucent background, a subtle border, a 22px backdrop blur, and layered shadows. Cyan and purple radial gradients appear behind the card, while the primary buttons use a gradient that moves between the two accent colors. Input focus states also change slightly between the login and signup sides.
JavaScript handles more than the card rotation. A delegated click listener reads the data-cr-authflip-target attribute from the switch buttons and calls switchView(). An isAnimating flag prevents another switch while the current animation is running. After 850 milliseconds, the script can focus the first input of the newly visible form when a fine pointer device is detected.
Accessibility is also considered during the flip. setFaceAccessibility() updates aria-hidden on both faces and temporarily gives focusable elements on the hidden side tabindex="-1". Their previous tabindex values are restored when that face becomes active. The password buttons also switch the input between password and text while updating their aria-label and aria-pressed attributes.
Form submission is intentionally prevented with event.preventDefault(), so this published version behaves as a front-end demo rather than sending credentials anywhere. A MutationObserver additionally initializes new .cr-authflip components if they are inserted into the document later.
Customizing This 3D Flip Login & Signup Form
Most visual settings are centralized in CSS variables or clearly defined component rules, so you can adapt the appearance without changing the flip logic.
- Change
--cr-af-bg,--cr-af-panel,--cr-af-text, and--cr-af-mutedto create a different dark or light color scheme. - Adjust
--cr-af-accentand--cr-af-accent-2to replace the cyan and purple accent colors. - Change the scene’s
perspectivevalue to alter how pronounced the 3D rotation appears. - Edit the card’s
0.82stransform transition to make the flip faster or slower. - Adjust the
28pxface border radius and panel padding to change the card shape and spacing. - Modify the
22pxbackdrop-filterblur to control the glass effect. - Change the input height, border radius, focus border, and focus shadow to match an existing form design.
- Update the primary button gradient, shadows, and hover translation for a different call-to-action style.
Where to Use This 3D Flip Login & Signup Form
This component works best when sign-in and registration need to stay within one compact interface rather than being separated into different pages.
- Account access pages that offer both login and registration.
- SaaS dashboards with a dedicated authentication screen.
- Portfolio or project demos that need an interactive account form.
- Membership websites where new and returning users share the same entry point.
- Web app onboarding flows with limited screen space.
- Front-end prototypes for testing authentication layouts before backend integration.
For another authentication layout with a different visual transition, the Animated S-Wave Login & Sign Up Form is a relevant CodeRipple component to explore. For production use, connect these forms to your authentication system and remove the demo preventDefault() behavior so valid submissions can reach the appropriate endpoint.
Frequently Asked Questions
How does the card flip between login and signup?
JavaScript toggles the is-signup class on .cr-authflip__card. CSS then applies rotateY(180deg) to the card. Because the signup face is already rotated 180 degrees and both faces hide their back sides, the correct form becomes visible during the rotation.
Does this component require JavaScript?
Yes. CSS creates the 3D appearance and transition, but JavaScript handles switching views, password visibility, accessibility states, focus management, animation locking, and dynamic component initialization.
Do the login and signup forms actually submit user data?
Not in the published demo. The submit listener calls event.preventDefault(), which stops the browser from submitting the forms. That line is intended to be removed when the forms are connected to real login and registration endpoints.
Is the form responsive and accessible?
The CSS includes breakpoints at 700px and 480px, with smaller dimensions, padding, perspective, and typography for narrower screens. It also respects prefers-reduced-motion. The JavaScript manages aria-hidden, tabindex values, password-button labels, and focus when switching between form faces.
The 3D Flip Login & Signup Form combines two authentication views in one responsive card, using CSS transforms for the visual flip and JavaScript for interaction, accessibility, and password controls.
