<form id="login-form">

    <svg class="logo">
        <use xlink:href="#logo">
    </svg>

    <h1>Sign In</h1>

    <div class="input email">
        <input type="text" value="email@gmail.com" placeholder=" ">
        <label>Email</label>
    </div>

    <div class="input password">
        <div class="dots"></div>
        <input type="password" placeholder=" ">
        <label>Password</label>
        <div class="cursor"></div>
        <div class="line">
            <svg>
                <use xlink:href="#line">
            </svg>
        </div>
        <div class="tick">
            <svg>
                <use xlink:href="#tick">
            </svg>
        </div>
    </div>

    <button type="submit" disabled>
        <svg viewBox="0 0 16 16">
            <circle stroke-opacity=".1" cx="8" cy="8" r="6"></circle>
            <circle class="load" cx="8" cy="8" r="6"></circle>
        </svg>
        <span>Submit</span>
    </button>

</form>
        
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
    <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44 44" id="logo">
        <path d="M33.0457936,22 L44,22 C44,34.1502645 34.1912695,44 22.0915872,44 C16.0417461,44 10.5646429,41.5375661 6.6,37.5563492 L14.3462931,29.7786761 C16.3285751,31.7689899 19.0669207,33 22.0915872,33 C25.1013453,33 27.827598,31.7810952 29.8075146,29.8080513 L22,22 L33.0457936,22.001001 C33.0457936,22.0006673 33.0457936,22.0003337 33.0457936,22 Z M21.9084128,0 C27.958756,0 33.4362661,2.4628426 37.400987,6.44464202 L29.6552,14.2228233 C27.6728001,12.2316284 24.9338388,11 21.9084128,11 C15.8585716,11 10.9542064,15.9248678 10.9542064,22 L10.954,22 L0,22 C0,9.8497355 9.8087305,0 21.9084128,0 Z"></path>
    </symbol>
    <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 22" id="line">
        <path d="M0,11 L180,11 C240,11.00344 300,13.6718267 360,19.00516 C450,27.00516 450,-4.99483997 540,3.00516003 C600,8.33849336 660,11.00344 720,11 L900,11"></path>
    </symbol>
    <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 28" id="tick">
        <path d="M3,12.5026479 L7,16.5026479 L13,9.50264792 C29.6216402,-12.0066881 40.3541164,26.00516 19,26.0026479 L-3.37507799e-13,26.0026479"></path>
    </symbol>
</svg>

<!-- dribbble - twitter -->
<a class="dribbble" href="https://dribbble.com/ai" target="_blank"><img src="https://cdn.dribbble.com/assets/dribbble-ball-mark-2bd45f09c2fb58dbbfb44766d5d1d07c5a12972d602ef8b32204d28fa3dda554.svg" alt=""></a>
<a class="twitter" target="_blank" href="https://twitter.com/aaroniker_me"><svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" viewBox="0 0 72 72"><path d="M67.812 16.141a26.246 26.246 0 0 1-7.519 2.06 13.134 13.134 0 0 0 5.756-7.244 26.127 26.127 0 0 1-8.313 3.176A13.075 13.075 0 0 0 48.182 10c-7.229 0-13.092 5.861-13.092 13.093 0 1.026.118 2.021.338 2.981-10.885-.548-20.528-5.757-26.987-13.679a13.048 13.048 0 0 0-1.771 6.581c0 4.542 2.312 8.551 5.824 10.898a13.048 13.048 0 0 1-5.93-1.638c-.002.055-.002.11-.002.162 0 6.345 4.513 11.638 10.504 12.84a13.177 13.177 0 0 1-3.449.457c-.846 0-1.667-.078-2.465-.231 1.667 5.2 6.499 8.986 12.23 9.09a26.276 26.276 0 0 1-16.26 5.606A26.21 26.21 0 0 1 4 55.976a37.036 37.036 0 0 0 20.067 5.882c24.083 0 37.251-19.949 37.251-37.249 0-.566-.014-1.134-.039-1.694a26.597 26.597 0 0 0 6.533-6.774z"></path></svg></a>
#login-form {
    --primary: #6D58FF;
    --primary-dark: #362A89;
    --dark: #2B3044;
    --grey-dark: #404660;
    --grey: #8A91B4;
    --grey-light: #A6ACCD;
    --light: #BBC1E1;
    --pale: #ECEFFC;
    --white: #FFFFFF;
    --red: #F04949;
    width: 100%;
    max-width: 180px;
    .logo {
        width: 44px;
        height: 44px;
        display: block;
        margin: 0 auto;
        fill: var(--primary);
    }
    h1 {
        margin: 24px 0;
        font-family: inherit;
        font-size: 20px;
        font-weight: bold;
        text-align: center;
        color: var(--dark);
    }
    .input {
        position: relative;
        label {
            pointer-events: none;
            font-size: 12px;
            font-weight: 500;
            line-height: 1.5;
            position: absolute;
            top: 8px;
            left: 0;
            transform-origin: 0 50%;
            transform: translateY(var(--label-y, 0)) scale(var(--label-scale, 1)) translateZ(0);
            transition: transform .3s, color .3s;
            color: var(--label-color, var(--grey-light));
        }
        input {
            width: 100%;
            border-radius: 0;
            -webkit-appearance: none;
            &:not(:placeholder-shown),
            &:focus {
                & + label {
                    --label-y: -17px;
                    --label-scale: .8;
                    --label-color: var(--grey);
                }
            }
        }
        &.email {
            margin-bottom: 16px;
            input {
                background: none;
                outline: none;
                border: none;
                color: var(--grey-dark);
                font-weight: 500;
                font-family: inherit;
                font-size: 13px;
                letter-spacing: .025em;
                line-height: 22px;
                caret-color: var(--primary);
                padding: 7px 0 5px 0;
                box-shadow: inset 0 -1px 0 0 var(--grey);
            }
        }
        &.password {
            height: 34px;
            .dots {
                position: absolute;
                display: flex;
                left: 0;
                top: 50%;
                transform: translateY(-2px);
                i {
                    width: 6px;
                    height: 6px;
                    border-radius: 50%;
                    background: var(--grey-dark);
                    display: block;
                    margin-right: 4px;
                    animation: var(--name, scale-in) .05s linear forwards;
                    &.remove {
                        --name: scale-out;
                    }
                    $i: 1;
                    @while $i <= 15 {
                        $delay: 400 - 6.5 * $i;
                        &:nth-child(#{$i}) {
                            --delay: #{$delay}ms;
                        }
                        $i: $i + 1;
                    }
                }
            }
            .cursor {
                position: absolute;
                height: 15px;
                width: 1px;
                left: 0;
                top: 10px;
                background: var(--primary);
                opacity: 0;
                transform: translateX(var(--cursor-x, 0));
                transition: transform var(--cursor-duration, .1s);
            }
            input {
                opacity: 0;
                padding: 0;
                position: absolute;
                left: 0;
                top: 0;
                bottom: 0;
                &:focus {
                    & + label + .cursor {
                        animation: cursor 1s ease infinite;
                    }
                }
            }
        }
        .line,
        .tick {
            pointer-events: none;
            position: absolute;
            left: var(--left, 0);
            bottom: var(--bottom, -10px);
            opacity: var(--opacity, 1);
            transition: opacity 0s linear var(--tick-opacity-delay, .5s);
            svg {
                stroke: var(--line-stroke, var(--grey));
                stroke-width: 1;
                fill: none;
                display: block;
                width: var(--width, 900px);
                height: var(--height, 22px);
                transform: translateX(var(--x, var(--line-x, 0)));
                transition: transform var(--line-x-duration, 0s) ease, stroke .3s;
            }
        }
        .line {
            overflow: hidden;
            width: 100%;
            transform-origin: 0 50%;
        }
        .tick {
            --left: 100%;
            --bottom: -1px;
            --width: 32px;
            --height: 28px;
            --x: -16px;
            --opacity: 0;
            svg {
                stroke: var(--tick-stroke, var(--grey));
                stroke-dasharray: 17 81;
                stroke-dashoffset: var(--tick-offset, 34px);
                transition: stroke-dashoffset .5s ease var(--tick-delay, 0s), stroke .5s ease var(--tick-delay, 0s);
            }
        }
    }
    button {
        border: none;
        outline: none;
        padding: 10px 0;
        margin: 24px 0 0 0;
        border-radius: 7px;
        color: var(--c, #fff);
        width: 100%;
        font-size: 14px;
        line-height: 16px;
        position: relative;
        font-family: inherit;
        font-weight: 500;
        background: var(--b, var(--primary-dark));
        transition: color .3s, background .3s;
        -webkit-appearance: none;
        -webkit-tap-highlight-color: transparent;
        cursor: pointer;
        &:disabled {
            --b: var(--pale);
            --c: var(--grey-light);
            cursor: not-allowed;
        }
        svg {
            width: 16px;
            height: 16px;
            display: block;
            position: absolute;
            left: 50%;
            top: 50%;
            margin: -8px 0 0 -8px;
            fill: none;
            stroke: currentColor;
            stroke-linecap: round;
            stroke-width: 1.5;
            opacity: var(--svg-o, 0);
            transform: translateY(var(--svg-y, -16px)) rotate(-90deg) scale(var(--svg-s, .7)) translateZ(0);
            transition: transform .3s, opacity .3s;
            circle {
                &:first-child {
                    stroke-opacity: .1;
                }
                &:last-child {
                    stroke-dasharray: 38px;
                    stroke-dashoffset: 114px;
                }
            }
        }
        span {
            display: inline-block;
            vertical-align: top;
            line-height: 16px;
            opacity: var(--span-o, 1);
            transform: translateY(var(--span-y, 0)) scale(var(--span-s, 1)) translateZ(0);
            transition: transform .3s, opacity .3s;
        }
    }
    &.processing {
        &:not(.error):not(.success) {
            button {
                --svg-y: 0;
                --svg-s: 1;
                --svg-o: 1;
                --span-y: 16px;
                --span-s: .7;
                --span-o: 0;
                svg {
                    circle {
                        &:last-child {
                            animation: load 1.2s linear .3s;
                        }
                    }
                }
            }
        }
        &.error {
            --line-x: -80%;
            --line-x-duration: 2s;
            --line-stroke: var(--red);
            --cursor-duration: 1s;
            .dots {
                i {
                    animation: flip .4s linear var(--delay) forwards;
                }
            }
        }
        &.success {
            .input {
                .tick {
                    --opacity: 1;
                    --tick-offset: 98px;
                    --tick-delay: .45s;
                    --tick-opacity-delay: 0s;
                    --tick-stroke: var(--primary);
                    animation: tick .4s linear forwards;
                }
                .line {
                    animation: line .5s linear forwards;
                }
            }
        }
    }
}

@keyframes tick {
    70%,
    80% {
        transform: translateX(-10px);
    }
}

@keyframes line {
    70% {
        transform: scaleX(.8);
    }
}

@keyframes flip {
    25% {
        transform: translateY(8px);
    }
    35% {
        transform: translateY(12px);
    }
    65% {
        transform: translateY(-4px);
    }
    100% {
        transform: translateY(-12px) scale(0);
    }
}

@keyframes load {
    from {
        stroke-dashoffset: 114px;
    }
    to {
        stroke-dashoffset: 38px;
    }
}

@keyframes scale-in {
    from {
        transform: scale(0);
    }
    to {
        transform: scale(1);
    }
}

@keyframes scale-out {
    from {
        transform: scale(1);
    }
    to {
        transform: scale(0);
    }
}

@keyframes cursor {
    50% {
        opacity: 1;
    }
}

html {
    box-sizing: border-box;
    -webkit-font-smoothing: antialiased;
}

* {
    box-sizing: inherit;
    &:before,
    &:after {
        box-sizing: inherit;
    }
}

// Center & dribbble
body {
    min-height: 100vh;
    display: flex;
    font-family: 'Inter', 'Inter UI', Arial;
    justify-content: center;
    align-items: center;
    background: #F6F8FF;
    .dribbble {
        position: fixed;
        display: block;
        right: 20px;
        bottom: 20px;
        img {
            display: block;
            height: 28px;
        }
    }
    .twitter {
        position: fixed;
        display: block;
        right: 64px;
        bottom: 14px;
        svg {
            width: 32px;
            height: 32px;
            fill: #1da1f2;
        }
    }
}
View Compiled
// correct password is `password` lol

const $ = (s, o = document) => o.querySelector(s);
const $$ = (s, o = document) => o.querySelectorAll(s);

const login = $('#login-form');
const passwordContainer = $('.password', login);
const password = $('input', passwordContainer);
const passwordList = $('.dots', passwordContainer);
const submit = $('button', login);

password.addEventListener('input', e => {
    if(password.value.length > $$('i', passwordList).length) {
        passwordList.appendChild(document.createElement('i'));
    }
    submit.disabled = !password.value.length;
    passwordContainer.style.setProperty('--cursor-x', password.value.length * 10 + 'px');
});

let pressed = false;

password.addEventListener('keydown', e => {

    if(pressed || login.classList.contains('processing') || (password.value.length > 14 && e.keyCode != 8 && e.keyCode != 13)) {
        e.preventDefault();
    }
    pressed = true;

    setTimeout(() => pressed = false, 50);

    if(e.keyCode == 8) {
        let last = $('i:last-child', passwordList);
        if(last !== undefined && last) {
            last.classList.add('remove');
            setTimeout(() => last.remove(), 50);
        }
    }

});

password.addEventListener('select', function() {
    this.selectionStart = this.selectionEnd;
});

login.addEventListener('submit', e => {

    e.preventDefault();

    if(!login.classList.contains('processing')) {
        login.classList.add('processing');
        setTimeout(() => {

            let cls = password.value == 'password' ? 'success' : 'error';
            console.log(password.value);

            login.classList.add(cls);
            setTimeout(() => {
                login.classList.remove('processing', cls);
                if(cls == 'error') {
                    password.value = '';
                    passwordList.innerHTML = '';
                    submit.disabled = true;
                }
            }, 2000);
            setTimeout(() => {
                if(cls == 'error') {
                    passwordContainer.style.setProperty('--cursor-x', 0 + 'px');
                }
            }, 600);

        }, 1500);
    }

});
Run Pen

External CSS

  1. https://cdn.jsdelivr.net/npm/inter-ui@3.11.0/inter.min.css

External JavaScript

This Pen doesn't use any external JavaScript resources.