Change Bootstrap Popover Position

If you have ever worked with Bootstrap’s popovers (popover.js), you may have had a hard time adjusting the position of a popover. As it turns out, it is a bit tricky to do so. The following example assumes that you want to adjust the position of a particular popover and therefore assigns a class to the popover such that it can be styled. Otherwise it is sufficient to style the .popover class.

First, let’s add the basics needed to get the popover to work, starting with a link that toggles the popover.

<a href="#" id="open-popover-link" title="Open Popover">Open Popover</a>

And now define the JavaScript code that opens the popover.

$('#open-popover-link').popover({
    placement: 'bottom',
    html: true,
    content: function() {
    	return $('#my-popover-container').html();
    },

    // We specify a template in order to set a class (an ID is overwritten) to the popover for styling purposes
    template: '<div class="popover my-popover" role="tooltip"><div class="arrow"></div><div class="popover-content"></div></div>'
});

Here we configure that the popover should be positioned below the element that triggers/opens it, and that we will specify custom HTML markup, as well as a function that returns this markup. Furthermore, we define a template into which our custom HTML markup will be inserted into (within .popover-content). We do this because we need to give the popover a class so that we can style it from within a CSS stylesheet. Unfortunately, we cannot add an ID, as this ID will be overwritten by Bootstrap Popover. Thus, we have to style with the selector popover.my-popover, which is okay anyways.

Below is the markup that we inject into the template markup that we defined in the above code snippet. To be clear, the HTML within the div below is returned by our content function.

<div id="my-popover-container" style="display: none;">
    <p>Any markup that you want here!</p>
</div>

Positioning the Bootstrap Popover

Now there are a few ways of going about this, which I will explain. First of all, you would think that you can just add position: relative; and position the popover relative to its normal position. However, this is not possible because Bootstrap Popover applies absolute positioning to the popover in order to position the popover near the triggering element, which means that your own position styling would be overwritten. Adding the !important keyword does not help, because then the popover would not be displayed anywhere near where it was supposed to (because this overwrites the absolute positioning), meaning that you would have to resort to some major “hacks” in your stylesheet.

Positioning with Margins

With relative positioning out of the picture, we don’t have that much to work with. However, what we can do is to adjust the margins of the popover instead, which is a less pretty way of doing relative positioning in this case. So to move the popover more to the left, we can add a negative margin-left, or a positive one to move it further to the right. Likewise, we can move the popover more up by adding a negative margin-top, and down by using a positive value. So, to move the popover 15px to the right and -20px up from its normal position, we can apply the following style.

.popover.my-popover {
    margin-left: 15px;
    margin-top: -20px;
	
    /* Or: margin: -20px 0 0 15px; */
}

Of course we can also apply other styles such as the height and width of the popover.

Creating a New Stacking Context

Before the following makes sense, let’s make sure that you know approximately absolute positioning works with stacking contexts. Simply put, when an element has a position other than static (such as absolute or relative), it creates a new stacking context, which means that child elements that are absolutely positioned are positioned relative to the parent rather than the root element.

This information about stacking contexts is actually be useful because the popover is positioned absolutely based on the parent with a non-static position (or otherwise the document). So if the parent creates a new stacking context (a position other than static), the top and left “attributes” of the popover are calculated based on the parent rather than the document. This makes it slightly more acceptable to overwrite these values with the !important keyword, rather than if we were positioning the popover absolutely relative to the entire document. However, whether or not this approach will work for you depends on your particular use case and markup. Either way, here is an example of this approach.

<div style="position: relative; height: 200px; width: 300px;">
    <a href="#" id="open-popover-link" title="Open Popover">Open Popover</a>

    <!-- The popover will be placed here with absolute positioning -->
</div>

And the CSS:

.popover.my-popover {
    top: 50px !important;
    left: 50px !important;
}

The above forces the popover to be placed 50px from the top and 50px from the left of the wrapping div. This may or may not be a useful approach for you.

Subscribing to the “shown.bs.popover” Event

Another solution is to subscribe to the shown.bs.popover event that is fired once the popover has been displayed, and update the position of the popover within this event handler. Something like the below positions the popover 100px lower and 100px more to the right of where it would otherwise be positioned.

$('#my-popover').on('shown.bs.popover', function() {
    // parseInt removes "px"
    var currentTop = parseInt($(this).css('top'));
    var currentLeft = parseInt($(this).css('left'));

    $(this).css({
        top: (currentTop + 100) + 'px',
        left: (currentLeft + 100) + 'px'
    });
});

The good thing about this approach is that it seems cleaner, but the major downside is that it introduces a “flicker” when the popover is repositioned. This is because the popover is first displayed at its initial position for a split second, whereafter the new styling is applied. This is what led me to look for the first solution that I presented.

Positioning The Popover Arrow

The position of the Bootstrap Popover’s arrow can be changed, too. The arrow is a child with the arrow class within the popover. It looks something like this (some markup has been removed for simplicity).

<div class="popover" role="tooltip">
    <div class="arrow" style="top: 50%;"></div>
    ...
</div>

Because Bootstrap Popovers have the popover class which have the position: absolute style, and the arrow class is absolutely positioned too, we can adjust the positioning of the arrow by using the left, right, top and bottom styles, like the following.

.popover.my-popover .arrow {
    left: 90% !important;
}

The above would be useful in the case that your popover is positioned below the element that triggered it and if you want the arrow to be positioned 90% to the right within the popover. In other cases, you would use the other styling options accordingly. We use the !important keyword to ensure that our style takes precedence over the inline styling that Bootstrap Popover applies itself. This way of positioning the arrow works because the popover creates a new stacking context, and the arrow is thus positioned based on this stacking context.

Conclusion

As you can see, advanced positioning of a Bootstrap Popover is not as easy as it should be. Hopefully new versions of Twitter Bootstrap will address this issue, but until then, these solutions will work. They are not the prettiest solutions in the world, but they do work for the time being, in the lack of “cleaner” solutions.

I am interested to hear if you have any improvements or other ways of accomplishing this, so please leave a comment if that is the case. Otherwise I hope this article helped you with your struggles! Thank you for reading.

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *