DEV Community

Cover image for Material dialog with CSS Animation
Nur Ilyas
Nur Ilyas

Posted on • Updated on

Material dialog with CSS Animation

"demo"

Refer to the full source code on github. Feedbacks are most welcome :)

I don't want to blabber too much so let's get right on to making the modal dialog inspired by Material Design.

Our version of modal dialog is made up of three components: the modal screen which also acts as a backdrop, the dialog itself & a form which the dialogue will display. The dialog contains 2 forms and both are set to hidden. The ModalDialog.js class will be responsible for displaying/hiding the respective forms.

    <div id="modal-screen" class="modal" hidden>

        <div class="dialog">

            <div id="user-form-one" class="hide" hidden>
                <p>Continue as . . .</p>
                <div id="alias-list"></div>
                <p class="seperator"><span>or</span></p>
                <button class="button">Create new user</button>
            </div>

            <div id="user-form-two" class="hide" hidden>
                <div class="info-alias">
                    <span>Enter your alias</span> 
                    <div class="tooltip" data-tip="Lorem Ipsum blablabla">
                        <img src="./help.svg"/>
                    </div>
                </div>
                <input class="input-alias" type="text" maxlength="35" placeholder="e.g. John Doe">
                <button class="button">Continue</button>
                <p class="error-message" hidden>Lorem Ipsum</p>
            </div>

        </div>

    </div>

To show/hide the modal screen, we will toggle the 'open' and 'close' class on the modal div element.

.open {
    animation: fade-in 0.5s forwards;

    .dialog {
        animation: slide-in 0.5s forwards;
    }
}

.close {
    animation: fade-out 0.5s forwards;

    .dialog {
        animation: slide-out 0.5s forwards;
    }
}

@keyframes fade-in {
    0% { opacity: 0; }
    100% { opacity: 1; }
}

@keyframes fade-out {
    100% { opacity: 0; }
}

@keyframes slide-in {
    100% { transform: translateY(100px); }
}

@keyframes slide-out {
    0% { transform: translateY(100px); }
    100% { transform: translateY(200%); }
}

Now on to animating the smooth scaling of the dialog box. The UserForm.js class is created as a base class for the 2 forms.

Inside show(), requestAnimationFrame function triggers a callback method, draw(), which performs the scaling animation of the dialog box and fading-in of the form.

But before show() can be called on the form that is about to be displayed, hide() method on the previous form is called first and a callback will be triggered once the fading-out animation has ended.

     /* In ModalDialog.js...
        userFormOne.hide(() => {
            userFormTwo.show();
        });
    */

class UserForm  {

    constructor(formId) {
        this.dialog = document.querySelector('.dialog');
        this.form = document.getElementById(formId);
        this.button = this.form.querySelector('.button');
        this.button.onclick = this.onButtonClick.bind(this);
        this.formHeight = null;
        this.formWidth = null;
    }

    onButtonClick(e) {
        e.stopPropagation();
        this.button.disabled = true;
    }

    hide(callback) {
        this.form.addEventListener('animationend', this.onFormHidden(callback));
        this.form.className = 'hide';

    }

    show() {
        this.form.hidden = false;
        this.button.disabled = false;    
        requestAnimationFrame(this.draw.bind(this));
    }

    draw() {
        this.dialog.style.width = this.getFormWidth();
        this.dialog.style.height = this.getFormHeight();
        this.form.className = 'show';
    }

    getFormHeight() {
        if(!this.formHeight) this.formHeight = this.form.offsetHeight + 'px';
        return this.formHeight;
    }

    getFormWidth() {
        if(!this.formWidth) this.formWidth = this.form.offsetWidth + 'px';
        return this.formWidth;
    }

    onFormHidden(callback) {
        const listener = () => {
            this.form.removeEventListener('animationend', listener);
            this.form.hidden = true;
            callback();
        }
        return listener;
    }
}

export default UserForm;

Take a look at UserFormOne.js and UserForm2.js to see which methods were overidden and also added functionalities.

For navigating between the forms, History API is used to keep track of that and onpopstate listener in the ModalDialog.js class will display the appropriate views.

I do apologize if this post seems rushed as I'm writing this at 3 in the morning and there's a lot of things to explain and I'm unsure if the code I wrote is proper(which is why I really want feedback). Also reason why I'm rushing through this is because I'm flying off for a month tomorrow leaving my laptop behind and I can't put this off any longer. Also, I find this a good way to improve on my English. Anyhow, It's been a pleasure and thank you so much for reading! Now, time to hit the hay ZzZzZz....

Discussion (0)