Building a Custom jQuery Modal

Building a Custom jQuery Modal To answer the first question, yes I still use jQuery. Why? Because it works and there is no need to overcomplicate what is a simple build. Onwards.

Now, there are many modals out there for you to choose from, but as you would expect they are very bloated. So I decided it was time to roll my own, this is the story of what I came up with.

Module Requirements

Before getting started on creating a modal, I had to get some requirements down. Without a set of requirements how would I be able to gauge the success of the module?

This was my requirements list:

  • Easily modifiable in terms of layout (template)
  • Modular layout
  • Standard set of styles
  • Reusable

Creating the Modal

The first part I thought about would be the usability of the module. How would I call a modal?

Most of the time, you want to show a modal in the callback of a click event, or at the end of an ajax call.

Like so?

$(function() {
    $('.cool-btn').on('click', function() {
        // Open a modal!!!
    });
});

So, taking this into consideration I decided that the best way to call would look a little like this:

var modal = require('./modal');

$(function() {
    $('.cool-btn').on('click', function() {
        modal.generate({
            'title' : 'My Modal'
        });
    });
});

Now, to me this code makes perfect sense. I click the button and in the callback I create a modal. It is as simple as that.

With the above code, I have included the Modal code as a separate module (remember the reusability statement?) so it was time to work up the “modal.generate” function.

I created a quick boilerplate for my modal.js file, which looked a little like this:

exports.generate = function(args) {
    var args = args || {};
}

$(function() {
    //
});

As you can see, I have my generate function along with a jQuery block that will house any logic specific to handling the Modal later on!

The next logical step for me was making sure the generate function had all the data I needed for the particular use case I had.

For the particular project, I needed a:

  • Title
  • Content Block
  • Button Text

So, I worked up the following:

exports.generate = function(args) {
    var args = args || {};

    args.title = args.title || 'Title';
    args.content = args.content || 'Content';
    args.button = args.button || 'Button';

    var content = '<div></div>';

    $('body').append(content);
}

$(function() {
    //
});

In the above, I am creating myself an object from the args that are passed through or falling back to a default. Pretty simple stuff, but highly effective.

Also in the above, I have already started thinking about how the data is going to be appended to the page. For this a simple append() call does the job perfectly.

With us now having all the data ready to go, it was time to template out my content variable ready for it to be appended. This took some trial and error, along with some CSS. Also, this is the section which is so project dependant so likely I will need to change this project to project. But here goes:

exports.generate = function(args) {
    var args = args || {};

    args.title = args.title || 'Title';
    args.content = args.content || 'Content';
    args.button = args.button || 'Button';

    var content = '<div class="modal-container">\
        <div class="overlay"></div>\
        <div class="modal">\
            <h2 class="title">' + args.title + '</h2>\
            <p class="content">\
                ' + args.content + '\
            </p>\
            <button class="btn btn-outline red">' + args.button + '</button>\
        </div>\
    </div>';

    $('body').append(content);
}

$(function() {
    //
});

The CSS to handle styling looks like so:

.modal-container {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 99;

    .overlay {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 100;
        background-color: rgba(0,0,0,0.85);
    }

    .modal {
        max-height: 75%;
        max-width: 90%;
        overflow-y: scroll;
        z-index: 200;
        background: #fff;
        padding: 20px;
        text-align: center;

        @media(max-width: 768px) {
            width: 90%;
        }

        @media(min-width: 768px) {
            max-width: 75%;
            padding: 40px;
        }
    }

    p {
        max-width: 75%;
        margin: 0 auto 20px auto;
    }

    .btn {
        margin-bottom: 0;
    }
}

One issue that I did run into was blurry text. To get around this issue I decided to centre the modal using flexbox. Problem solved, my Modal looked great but I couldn’t close it! That can be solved in a quick function, bringing my total modal.js file to be the following:

exports.generate = function(args) {
    var args = args || {};

    args.title = args.title || 'Title';
    args.content = args.content || 'Content';
    args.button = args.button || 'Button';

    var content = '<div class="modal-container">\
        <div class="overlay"></div>\
        <div class="modal">\
            <h2 class="title">' + args.title + '</h2>\
            <p class="content">\
                ' + args.content + '\
            </p>\
            <button class="btn btn-outline red">' + args.button + '</button>\
        </div>\
    </div>';

    $('body').append(content);
}

$(function() {
    $('body').on('click', '.modal button, .modal-container .overlay', function() {
        $(this).closest('.modal-container').remove();
    });
});

This function allows me to click the button or anywhere outside the modal to close it. Again, this is sort of project dependant and you may include a dedicated close button.

Potential Improvements

One of my requirements was to make it easily modifiable, I am confident in the ability to modify the module. However, in it’s current state I believe the layout is too opinionated to ship as say an NPM module.

To improve, I would look to create an template file and have some sort of init command. This would allow the Modal base code to be shared more easily cross project. But, with each added layer of complexity it takes me away from the initial goal of making a really lightweight custom jQuery Modal.

The way forward for this is definitely to work out the templating extendability and do some performance benchmarks to see any negative effects. But that is for another blog post!

Conclusion I set out to create a simple, reusable jQuery modal. After writing this blog post I am happy to believe that this was achieved. There are many improvements to the code included in this post, but for me it ticks all the boxes in relation to my requirements.