How to Implement a Password Reveal

Obfuscated Password
Obfuscated Password
Revealled Password
Revealled Password
graph TD A[Input] --> C[canReveal:=false] C -.->|onfocus| B{Check value} B --> |length>0| F(Listen) B --> |length=0| D(canReveal:=true) F -.-> |onblur| E(End) F -.-> |oninput| B B --> |canReveal & length>0| I(Show Reveal cue) I --> J(Listen) D --> F(Listen) J -.-> |on reveal| G(Show password) G --> F J -.-> |on unreveal| H(Obfuscate password) H --> F
document.querySelectorAll('input[type=password]').forEach(function (input) {
    const cue = document.createElement("span");
    cue.setAttribute('aria-hidden', 'true');

    const wrapper = document.createElement("span");
    wrapper.classList.add('input-wrapper');

    input.parentNode.insertBefore(wrapper, input);
    wrapper.appendChild(input);
    wrapper.appendChild(cue);

    let reveal = false;
    const checkReveal = function () {
        input.dataset.reveal = Boolean(reveal |= !input.value);
        input.dataset.valueLength = input.value.length;
    };

    input.addEventListener('focus', function () {
        input.addEventListener('input', checkReveal);
        input.dataset.reveal = Boolean(reveal = !input.value);
        input.dataset.valueLength = input.value.length;
    }, { passive: true });
    input.addEventListener('blur', function () {
        input.setAttribute('type', 'password');
        input.dataset.reveal = reveal = false;
        input.removeEventListener('input', checkReveal);
    }, { passive: true });

    cue.addEventListener('mousedown', function (e) {
        e.preventDefault();
        const type = input.getAttribute('type') === 'password' ? 'text' : 'password';
        input.setAttribute('type', type);
    });
});
.input-wrapper {
    position: relative;
    display: block;
}

input[data-reveal]::-ms-reveal, input[data-reveal] + [aria-hidden] {
    display: none;
}

input[data-reveal=true]:not([data-value-length='0']) {
    padding-right: calc(#{$fa-fw-width} + 1rem);

    & + [aria-hidden] {
        speak: none;
        font-family: FontIcons;
        font-weight: normal;
        box-sizing: content-box;
        padding: 0.25rem 0.5rem;
        height: calc(100% - 0.5rem);
        width: $fa-fw-width;
        position: absolute;
        top: 0;
        right: 0;
        display: flex;
        justify-content: center;
        align-content: center;
        flex-direction: column;
        z-index: 1000;
    }

    &[type=password] + [aria-hidden]::before {
        content: fa-content($fa-var-eye);
    }

    &[type=text] + [aria-hidden]:before {
        content: fa-content($fa-var-eye-slash);
    }
}

Leave a comment

Please note that we won't show your email to others, or use it for sending unwanted emails. We will only use it to render your Gravatar image and to validate you as a real person.