17 / 30
All 30 in 30 CSS Login Forms
- 01Split-Screen Brand Hero
- 02Multi-Tenant Account Switcher
- 03Floating Label Login
- 04Web3 Native Wallet Connect
- 05Stripe-Inspired Minimalist
- 06OAuth Social Login
- 07Magic Link
- 08Aurora Glow
- 09Neon Synthwave
- 10Liquid Slide
- 11Card Flip Reset
- 12Terminal Prompt
- 13Floating Pill
- 14Gradient Border
- 15Side Panel
- 16Social First
- 17Animated Mascot
- 18Compact Modal
- 19Glass Frosted
- 20Step-by-Step
- 21Animated Gradient Border
- 22Vault Lock
- 23Brutalist Stamp
- 24Show Password Toggle
- 25OTP Verify
- 26Strength Meter
- 27Pin Pad
- 28Inline Validation
- 29Constellation
- 30Biometric Prompt
Animated Mascot
A playful character sits above the form and reacts to the user: its eyes follow the email field and its hands shoot up to cover its eyes the moment the password field is focused — the friendly, conversion-boosting login, all in CSS.
Build interactive UI like this from scratch: 20 HTML, CSS & JavaScript projects
ZTM · JavaScript Web Projects · 30‑day money-back guarantee · Affiliate link
The code
<section class="lf-17">
<form class="lf-17__card" novalidate>
<div class="lf-17__mascot" aria-hidden="true">
<svg viewBox="0 0 120 120">
<circle class="lf-17__body" cx="60" cy="60" r="44"/>
<circle class="lf-17__ear" cx="30" cy="26" r="12"/><circle class="lf-17__ear" cx="90" cy="26" r="12"/>
<circle class="lf-17__eye" cx="46" cy="56" r="7"/><circle class="lf-17__eye" cx="74" cy="56" r="7"/>
<ellipse class="lf-17__nose" cx="60" cy="72" rx="7" ry="5"/>
<path class="lf-17__arm lf-17__arm--l" d="M22 96 q10 -14 26 -8"/>
<path class="lf-17__arm lf-17__arm--r" d="M98 96 q-10 -14 -26 -8"/>
</svg>
</div>
<h1 class="lf-17__h">Hey there!</h1>
<label class="lf-17__field lf-17__field--email"><span class="lf-17__label">Email</span>
<input type="email" autocomplete="email" placeholder="you@company.com" required></label>
<label class="lf-17__field lf-17__field--pw"><span class="lf-17__label">Password</span>
<input type="password" autocomplete="current-password" placeholder="••••••••" required></label>
<button class="lf-17__submit" type="submit">Log in</button>
</form>
</section><section class="lf-17">
<form class="lf-17__card" novalidate>
<div class="lf-17__mascot" aria-hidden="true">
<svg viewBox="0 0 120 120">
<circle class="lf-17__body" cx="60" cy="60" r="44"/>
<circle class="lf-17__ear" cx="30" cy="26" r="12"/><circle class="lf-17__ear" cx="90" cy="26" r="12"/>
<circle class="lf-17__eye" cx="46" cy="56" r="7"/><circle class="lf-17__eye" cx="74" cy="56" r="7"/>
<ellipse class="lf-17__nose" cx="60" cy="72" rx="7" ry="5"/>
<path class="lf-17__arm lf-17__arm--l" d="M22 96 q10 -14 26 -8"/>
<path class="lf-17__arm lf-17__arm--r" d="M98 96 q-10 -14 -26 -8"/>
</svg>
</div>
<h1 class="lf-17__h">Hey there!</h1>
<label class="lf-17__field lf-17__field--email"><span class="lf-17__label">Email</span>
<input type="email" autocomplete="email" placeholder="you@company.com" required></label>
<label class="lf-17__field lf-17__field--pw"><span class="lf-17__label">Password</span>
<input type="password" autocomplete="current-password" placeholder="••••••••" required></label>
<button class="lf-17__submit" type="submit">Log in</button>
</form>
</section>.lf-17,
.lf-17 *,
.lf-17 *::before,
.lf-17 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.lf-17 {
--accent: oklch(0.62 0.17 40);
--radius: 12px;
--field-h: 48px;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
background: #fdf3ea;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.lf-17__card {
position: relative;
width: min(340px,100%);
background: #fff;
border: 1px solid #f0e2d5;
border-radius: 20px;
padding: 64px 30px 32px;
display: flex;
flex-direction: column;
gap: 14px;
box-shadow: 0 24px 56px -38px rgba(120,60,20,.5);
}
.lf-17__mascot {
position: absolute;
top: -46px;
left: 50%;
transform: translateX(-50%);
width: 96px;
height: 96px;
}
.lf-17__mascot svg {
width: 100%;
height: 100%;
overflow: visible;
}
.lf-17__body {
fill: oklch(0.7 0.13 55);
}
.lf-17__ear {
fill: oklch(0.66 0.14 50);
}
.lf-17__eye {
fill: #2a1a10;
transition: transform .2s;
}
.lf-17__nose {
fill: #3a2418;
}
.lf-17__arm {
stroke: oklch(0.66 0.14 50);
stroke-width: 12;
stroke-linecap: round;
fill: none;
transform-origin: center;
transition: transform .28s cubic-bezier(.4,0,.2,1);
}
.lf-17__h {
font-size: 22px;
font-weight: 700;
color: #4a2c15;
text-align: center;
}
.lf-17__field {
display: flex;
flex-direction: column;
gap: 6px;
}
.lf-17__label {
font-size: 13px;
font-weight: 600;
color: #7a5638;
}
.lf-17__field input {
height: var(--field-h);
border: 1.5px solid #ecd9c7;
border-radius: var(--radius);
padding: 0 14px;
font-size: 15px;
color: #4a2c15;
background: #fffdfb;
transition: border-color .18s,box-shadow .18s;
}
.lf-17__field input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px oklch(0.62 0.17 40/.18);
}
.lf-17__submit {
height: var(--field-h);
margin-top: 4px;
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-17__submit:hover {
filter: brightness(1.06);
}
.lf-17__submit:active {
transform: scale(.985);
}
.lf-17__submit:focus-visible {
outline: 3px solid oklch(0.62 0.17 40/.5);
outline-offset: 2px;
}
.lf-17__field--email:focus-within ~ * .lf-17__eye,
.lf-17__card:has(.lf-17__field--email:focus-within) .lf-17__eye {
transform: translateY(3px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__arm--l {
transform: rotate(-62deg) translate(6px,-30px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__arm--r {
transform: rotate(62deg) translate(-6px,-30px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__eye {
transform: scaleY(.15);
}
@media (prefers-reduced-motion: reduce) {
.lf-17__arm,
.lf-17__eye {
transition: none;
}
}.lf-17,
.lf-17 *,
.lf-17 *::before,
.lf-17 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.lf-17 {
--accent: oklch(0.62 0.17 40);
--radius: 12px;
--field-h: 48px;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
background: #fdf3ea;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.lf-17__card {
position: relative;
width: min(340px,100%);
background: #fff;
border: 1px solid #f0e2d5;
border-radius: 20px;
padding: 64px 30px 32px;
display: flex;
flex-direction: column;
gap: 14px;
box-shadow: 0 24px 56px -38px rgba(120,60,20,.5);
}
.lf-17__mascot {
position: absolute;
top: -46px;
left: 50%;
transform: translateX(-50%);
width: 96px;
height: 96px;
}
.lf-17__mascot svg {
width: 100%;
height: 100%;
overflow: visible;
}
.lf-17__body {
fill: oklch(0.7 0.13 55);
}
.lf-17__ear {
fill: oklch(0.66 0.14 50);
}
.lf-17__eye {
fill: #2a1a10;
transition: transform .2s;
}
.lf-17__nose {
fill: #3a2418;
}
.lf-17__arm {
stroke: oklch(0.66 0.14 50);
stroke-width: 12;
stroke-linecap: round;
fill: none;
transform-origin: center;
transition: transform .28s cubic-bezier(.4,0,.2,1);
}
.lf-17__h {
font-size: 22px;
font-weight: 700;
color: #4a2c15;
text-align: center;
}
.lf-17__field {
display: flex;
flex-direction: column;
gap: 6px;
}
.lf-17__label {
font-size: 13px;
font-weight: 600;
color: #7a5638;
}
.lf-17__field input {
height: var(--field-h);
border: 1.5px solid #ecd9c7;
border-radius: var(--radius);
padding: 0 14px;
font-size: 15px;
color: #4a2c15;
background: #fffdfb;
transition: border-color .18s,box-shadow .18s;
}
.lf-17__field input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px oklch(0.62 0.17 40/.18);
}
.lf-17__submit {
height: var(--field-h);
margin-top: 4px;
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-17__submit:hover {
filter: brightness(1.06);
}
.lf-17__submit:active {
transform: scale(.985);
}
.lf-17__submit:focus-visible {
outline: 3px solid oklch(0.62 0.17 40/.5);
outline-offset: 2px;
}
.lf-17__field--email:focus-within ~ * .lf-17__eye,
.lf-17__card:has(.lf-17__field--email:focus-within) .lf-17__eye {
transform: translateY(3px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__arm--l {
transform: rotate(-62deg) translate(6px,-30px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__arm--r {
transform: rotate(62deg) translate(-6px,-30px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__eye {
transform: scaleY(.15);
}
@media (prefers-reduced-motion: reduce) {
.lf-17__arm,
.lf-17__eye {
transition: none;
}
}/* No JavaScript — :has() + :focus-within move the mascot's SVG arms and eyes on field focus. */
/* No JavaScript — :has() + :focus-within move the mascot's SVG arms and eyes on field focus. */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: Animated Mascot
Source: https://codefronts.com/components/css-login-forms/animated-mascot/
A playful character sits above the form and reacts to the user: its eyes follow the email field and its hands shoot up to cover its eyes the moment the password field is focused — the friendly, conversion-boosting login, all in CSS.
## HTML
```html
<section class="lf-17">
<form class="lf-17__card" novalidate>
<div class="lf-17__mascot" aria-hidden="true">
<svg viewBox="0 0 120 120">
<circle class="lf-17__body" cx="60" cy="60" r="44"/>
<circle class="lf-17__ear" cx="30" cy="26" r="12"/><circle class="lf-17__ear" cx="90" cy="26" r="12"/>
<circle class="lf-17__eye" cx="46" cy="56" r="7"/><circle class="lf-17__eye" cx="74" cy="56" r="7"/>
<ellipse class="lf-17__nose" cx="60" cy="72" rx="7" ry="5"/>
<path class="lf-17__arm lf-17__arm--l" d="M22 96 q10 -14 26 -8"/>
<path class="lf-17__arm lf-17__arm--r" d="M98 96 q-10 -14 -26 -8"/>
</svg>
</div>
<h1 class="lf-17__h">Hey there!</h1>
<label class="lf-17__field lf-17__field--email"><span class="lf-17__label">Email</span>
<input type="email" autocomplete="email" placeholder="you@company.com" required></label>
<label class="lf-17__field lf-17__field--pw"><span class="lf-17__label">Password</span>
<input type="password" autocomplete="current-password" placeholder="••••••••" required></label>
<button class="lf-17__submit" type="submit">Log in</button>
</form>
</section>
```
## CSS
```css
.lf-17,
.lf-17 *,
.lf-17 *::before,
.lf-17 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.lf-17 {
--accent: oklch(0.62 0.17 40);
--radius: 12px;
--field-h: 48px;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
background: #fdf3ea;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.lf-17__card {
position: relative;
width: min(340px,100%);
background: #fff;
border: 1px solid #f0e2d5;
border-radius: 20px;
padding: 64px 30px 32px;
display: flex;
flex-direction: column;
gap: 14px;
box-shadow: 0 24px 56px -38px rgba(120,60,20,.5);
}
.lf-17__mascot {
position: absolute;
top: -46px;
left: 50%;
transform: translateX(-50%);
width: 96px;
height: 96px;
}
.lf-17__mascot svg {
width: 100%;
height: 100%;
overflow: visible;
}
.lf-17__body {
fill: oklch(0.7 0.13 55);
}
.lf-17__ear {
fill: oklch(0.66 0.14 50);
}
.lf-17__eye {
fill: #2a1a10;
transition: transform .2s;
}
.lf-17__nose {
fill: #3a2418;
}
.lf-17__arm {
stroke: oklch(0.66 0.14 50);
stroke-width: 12;
stroke-linecap: round;
fill: none;
transform-origin: center;
transition: transform .28s cubic-bezier(.4,0,.2,1);
}
.lf-17__h {
font-size: 22px;
font-weight: 700;
color: #4a2c15;
text-align: center;
}
.lf-17__field {
display: flex;
flex-direction: column;
gap: 6px;
}
.lf-17__label {
font-size: 13px;
font-weight: 600;
color: #7a5638;
}
.lf-17__field input {
height: var(--field-h);
border: 1.5px solid #ecd9c7;
border-radius: var(--radius);
padding: 0 14px;
font-size: 15px;
color: #4a2c15;
background: #fffdfb;
transition: border-color .18s,box-shadow .18s;
}
.lf-17__field input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px oklch(0.62 0.17 40/.18);
}
.lf-17__submit {
height: var(--field-h);
margin-top: 4px;
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-17__submit:hover {
filter: brightness(1.06);
}
.lf-17__submit:active {
transform: scale(.985);
}
.lf-17__submit:focus-visible {
outline: 3px solid oklch(0.62 0.17 40/.5);
outline-offset: 2px;
}
.lf-17__field--email:focus-within ~ * .lf-17__eye,
.lf-17__card:has(.lf-17__field--email:focus-within) .lf-17__eye {
transform: translateY(3px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__arm--l {
transform: rotate(-62deg) translate(6px,-30px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__arm--r {
transform: rotate(62deg) translate(-6px,-30px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__eye {
transform: scaleY(.15);
}
@media (prefers-reduced-motion: reduce) {
.lf-17__arm,
.lf-17__eye {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — :has() + :focus-within move the mascot's SVG arms and eyes on field focus. */
```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: Animated Mascot
Source: https://codefronts.com/components/css-login-forms/animated-mascot/
A playful character sits above the form and reacts to the user: its eyes follow the email field and its hands shoot up to cover its eyes the moment the password field is focused — the friendly, conversion-boosting login, all in CSS.
## HTML
```html
<section class="lf-17">
<form class="lf-17__card" novalidate>
<div class="lf-17__mascot" aria-hidden="true">
<svg viewBox="0 0 120 120">
<circle class="lf-17__body" cx="60" cy="60" r="44"/>
<circle class="lf-17__ear" cx="30" cy="26" r="12"/><circle class="lf-17__ear" cx="90" cy="26" r="12"/>
<circle class="lf-17__eye" cx="46" cy="56" r="7"/><circle class="lf-17__eye" cx="74" cy="56" r="7"/>
<ellipse class="lf-17__nose" cx="60" cy="72" rx="7" ry="5"/>
<path class="lf-17__arm lf-17__arm--l" d="M22 96 q10 -14 26 -8"/>
<path class="lf-17__arm lf-17__arm--r" d="M98 96 q-10 -14 -26 -8"/>
</svg>
</div>
<h1 class="lf-17__h">Hey there!</h1>
<label class="lf-17__field lf-17__field--email"><span class="lf-17__label">Email</span>
<input type="email" autocomplete="email" placeholder="you@company.com" required></label>
<label class="lf-17__field lf-17__field--pw"><span class="lf-17__label">Password</span>
<input type="password" autocomplete="current-password" placeholder="••••••••" required></label>
<button class="lf-17__submit" type="submit">Log in</button>
</form>
</section>
```
## CSS
```css
.lf-17,
.lf-17 *,
.lf-17 *::before,
.lf-17 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.lf-17 {
--accent: oklch(0.62 0.17 40);
--radius: 12px;
--field-h: 48px;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
background: #fdf3ea;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.lf-17__card {
position: relative;
width: min(340px,100%);
background: #fff;
border: 1px solid #f0e2d5;
border-radius: 20px;
padding: 64px 30px 32px;
display: flex;
flex-direction: column;
gap: 14px;
box-shadow: 0 24px 56px -38px rgba(120,60,20,.5);
}
.lf-17__mascot {
position: absolute;
top: -46px;
left: 50%;
transform: translateX(-50%);
width: 96px;
height: 96px;
}
.lf-17__mascot svg {
width: 100%;
height: 100%;
overflow: visible;
}
.lf-17__body {
fill: oklch(0.7 0.13 55);
}
.lf-17__ear {
fill: oklch(0.66 0.14 50);
}
.lf-17__eye {
fill: #2a1a10;
transition: transform .2s;
}
.lf-17__nose {
fill: #3a2418;
}
.lf-17__arm {
stroke: oklch(0.66 0.14 50);
stroke-width: 12;
stroke-linecap: round;
fill: none;
transform-origin: center;
transition: transform .28s cubic-bezier(.4,0,.2,1);
}
.lf-17__h {
font-size: 22px;
font-weight: 700;
color: #4a2c15;
text-align: center;
}
.lf-17__field {
display: flex;
flex-direction: column;
gap: 6px;
}
.lf-17__label {
font-size: 13px;
font-weight: 600;
color: #7a5638;
}
.lf-17__field input {
height: var(--field-h);
border: 1.5px solid #ecd9c7;
border-radius: var(--radius);
padding: 0 14px;
font-size: 15px;
color: #4a2c15;
background: #fffdfb;
transition: border-color .18s,box-shadow .18s;
}
.lf-17__field input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px oklch(0.62 0.17 40/.18);
}
.lf-17__submit {
height: var(--field-h);
margin-top: 4px;
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-17__submit:hover {
filter: brightness(1.06);
}
.lf-17__submit:active {
transform: scale(.985);
}
.lf-17__submit:focus-visible {
outline: 3px solid oklch(0.62 0.17 40/.5);
outline-offset: 2px;
}
.lf-17__field--email:focus-within ~ * .lf-17__eye,
.lf-17__card:has(.lf-17__field--email:focus-within) .lf-17__eye {
transform: translateY(3px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__arm--l {
transform: rotate(-62deg) translate(6px,-30px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__arm--r {
transform: rotate(62deg) translate(-6px,-30px);
}
.lf-17__card:has(.lf-17__field--pw:focus-within) .lf-17__eye {
transform: scaleY(.15);
}
@media (prefers-reduced-motion: reduce) {
.lf-17__arm,
.lf-17__eye {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — :has() + :focus-within move the mascot's SVG arms and eyes on field focus. */
```How this works
The mascot is an inline SVG whose parts (eyes, arms) are targeted by CSS classes, keeping presentation fully separate from any handlers. Reactions are driven by real form state: :focus-within on the email field nudges the eyes; :focus-within on the password field triggers the .is-hiding pose — arms rotate up over the eyes via transform.
Because the selectors read native focus, there is no keystroke JavaScript — the character responds to Tab-focus too, so keyboard users get the same delight. All motion is transform, so it's smooth and reflow-free.
The SVG is aria-hidden (decorative); the form remains a plain accessible form underneath.
Make it yours
- Recolour the mascot via the SVG fill tokens.
- Tune the arm-raise angle / eye nudge in the transform rules.
- Add an
.is-typingpose keyed off:not(:placeholder-shown). - Swap the character art while keeping the class hooks.
Gotchas — read before shipping
- Drive reactions from
:focus-withinso keyboard focus animates the mascot too, not just mouse. - Keep the SVG
aria-hidden— it's decoration, not content. - Use
transformfor arms/eyes so the character never triggers layout reflow.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 15.4+ | 121+ | 111+ |
Floor set by :has(), oklch() as this demo is written. The core technique itself goes back further — Chrome 49+.
:focus-within + SVG transforms are universally supported; reactions need no JS.