05
Mar '19

I spent some time messing about with Bootstrap popovers, and other similar tools but was finding that they tended to be overly complicated to use and skin, and also mostly wouldn’t allow form elements to be inside them. I found myself with a task where I was very tight on space and needed to add several textareas to my form. A popover was the obvious choice, but many relied on convoluted attributes on the trigger element or involved javascript handlers. Even more importantly most tend to destroy the popover when it is closed, which is clearly no use I want a form element in there.

After a bit of playing around I came up with this script myself:

CSS:

.popover-container {
    position: relative;
}

.popover-content {
    z-index: 10000;
    border: 1px solid #555555;
    padding: 8px;
    margin-top: 10px;
    width: 300px;
    position: absolute;
    left: -1000000px;
}

.popover-content.open {
    left: -150px;
}

.popover-content.open:after {
    content: '';
    display: block;
    position: absolute;
    top: -6px;
    left: 150px;
    width: 10px;
    height: 10px;
    background: #FFFFFF;
    border-right:1px solid #555555;
    border-top:1px solid #555555;
    -moz-transform:rotate(-45deg);
    -webkit-transform:rotate(-45deg);
}

JS:

$().ready(function() {

    $('.popover-container').on('click', 'button', function() {
        var parent = $(this).parents('.popover-container');
        var content = parent.find('.popover-content');

        if(content.hasClass('open')) {
            closePopover(content);
        }
        else {
            //Clear down any others first
            $('.popover-content.open').each(function() {
                closePopover($this);
            });

            content.addClass('open');

            var offset = 150 - (parent.width() / 2) - 2;

            content.css('left', '-' + offset + 'px');
        }
    });

    //Close on blur
    $('.popover-container').on('blur', '.popover-content', function() {
        closePopover($(this));
    });

    //Close on escape key
    $(document).keyup(function(e) {
        if (e.keyCode === 27) {
            $('.popover-content.open').each(function() {
                closePopover($(this));
            });
        }
    });
});

function closePopover(element) {
    element.removeClass('open');
    element.css('left', '');
}

Example HTML:

<div class="popover-container">

    <button type="button" class="btn btn-xs btn-default">
        Show Popover
    </button>

    <div class="popover-content">
        <div class="form-group">
            <p>This is my popover</p>
            <textarea name="my-textarea"></textarea>
        </div>
    </div>
</div>

Note that the CSS and JS above are based around the popover being 300px wide. You can change this to whatever you like, but bear in mind that the centering (the 150px offsets) needs to be adjusted in a corresponding way.