77

I want to use a data- element (eg: data-class or similar) to attach a new class (Or ID, I'm not picky anymore!) to the top-level popover <div>. The code I currently have is as follows:

jQuery:

$('a[rel=popover]')
    .popover({
        placement : 'bottom',
        trigger : 'hover'
    })
    .click(function(e) {
        e.preventDefault()
    });

HTML:

<a href="" rel="popover" data-class="dynamic-class" title="Title goes here" data-content="Content goes here">

And ideally the kind of HTML I would have spit out, is something like this:

<div class="popover ... dynamic-class">
    <!-- remainder of the popover code as per usual -->
</div>

Is this something I can do?

The documentation on the bootstrap site for popovers is a bit sparse, so it's taken me a while just to get to this point, unfortunately.

starball
  • 20,030
  • 7
  • 43
  • 238
Kate
  • 1,638
  • 1
  • 14
  • 15
  • I will be selecting my answer as correct when the time limit allows me to :) So see below for the time being. – Kate Aug 30 '12 at 12:52
  • Did you ever find a solution that doesn't involve manipulating source code? – yuvi Mar 11 '14 at 14:11

22 Answers22

78

You can do this without hacking Bootstrap and without changing the template either, by grabbing the popover object from the caller's data and accessing its $tip property.

$('a[rel=popover]')
  .popover({ placement: 'bottom', trigger: 'hover' })
  .data('bs.popover')
  .tip()
  .addClass('my-super-popover');
Rabih Kodeih
  • 9,361
  • 11
  • 47
  • 55
Seth Jeffery
  • 1,110
  • 1
  • 8
  • 8
  • I'm assuming this is new in Bootstrap. As you may've noticed, my original question was back in August 2012, when I believe I was using v2.3.0 - so your solution was not possible back then. It is also not allowing me to add a dynamic class to each different popover - your way adds the same class name to every popover. So irrelevant to the original question. – Kate Nov 11 '13 at 01:54
  • 1
    I don't know when they changed it, but I used this method on bootstrap v2.3.2. If you want to add a different class name on every popover, just change the point at which you access the $tip property, for example move it into your click callback! :) – Seth Jeffery Dec 04 '13 at 11:47
  • 2
    Note that the data name is changed to `'bs.popover'` in Bootstrap 3. – István Ujj-Mészáros Dec 08 '13 at 18:44
  • 7
    on v2.3.1, `$tip` should be replaced with `tip()` – Khoi Jan 21 '14 at 03:45
  • 3
    Like tranver said below, in newer Boostrap you need to use `bs.popover` and `tip()`, like `$(element).popover({...}).data("bs.popover").tip()` – Gavin May 15 '14 at 10:31
  • 1
    Thanks guys I've upgraded my answer. – Seth Jeffery Aug 01 '14 at 14:21
  • 3
    this should be the answer of this question – Sergio Marcelino Sep 07 '14 at 16:55
  • 1
    In v4 `.tip()` should be replaced with just `.tip`. To get the element on an related event: ```$('a[rel=popover]').on('show.bs.popover', function(e) { var popover = $(this).data('bs.popover').tip; }); ``` – Steve Meisner Dec 03 '16 at 13:03
  • Thanks, I'll wait until it comes out of alpha. You never know it might change! ;) – Seth Jeffery Dec 03 '16 at 20:15
  • This method does not work when used in conjunction when deferring, i.e. `$('body').popover({ selector: 'a[rel=popover]' })...` – shooftie Jan 11 '17 at 17:53
  • 1
    v4 beta is released, so I've updated with @SteveMeisner's modification. – Seth Jeffery Aug 15 '17 at 14:12
  • 1
    This only adds the class to the first popover on the page, should I loop through all the elements? – theyuv Nov 02 '17 at 12:35
  • 5
    Yes, because `.data(...)` retrieves the data value for the first matched item. If you want to set on all elements you could either use each `.each(function() { $(this).data('bs.popover').tip.addClass('my-super-popover'); })` or perhaps map `.map(function() { return $(this).data('bs.popover').tip; }).addClass('my-super-popover');` – Seth Jeffery Mar 21 '18 at 09:51
  • 2
    I have upgraded to **Bootstrap4** and it works as: `$('[data-toggle="popover"]') .each(function() { $($(this).popover('show') .popover('hide') .data('bs.popover') .tip ).addClass('custom-large-popover'); }); ` Some remarks: As **tip** returns the dom element, we need to wrap it in a jQuery object: `$(element returned by tip).addClass()` Strangely enough, if the popover had not been showed, the tip element was not initialized, so I am showing it and hiding it. Other approaches are more than welcome! – Marc Vidal Moreno Aug 28 '18 at 13:17
  • Be also aware, that there is a Pull Request to add a class as an option that maybe someday is merged. To be followed at: https://github.com/twbs/bootstrap/pull/23874/ – Marc Vidal Moreno Aug 28 '18 at 13:23
56

There is another way to do this in version 2.3 that is quite simple actually. You override the default template to include the class to the container.

var pop = $('a', this.el).popover({
  trigger: 'click'
  , template: '<div class="popover awesome-popover-class"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
});
cbaigorri
  • 2,467
  • 25
  • 26
22

Based on what @bchhun wrote and a lot of head scratching, I felt I should answer my own question, as I got it working. I also noticed this had been favourited and liked, so I hope I'm helping someone else who is a newbie at jQuery like myself.

In the current Bootstrap build [v2.1.0], the scripts are all consolidated. So if you have included all of the scripts in your build (and not edited any new lines/taken some out), then head to line 1108 of the un-minified .js file. You'll find the following bit of code:

$tip
  .css(tp)
  .addClass(placement)
  .addClass('in')

You're going to be adding a new line to this, which is:

  .addClass(this.$element.attr("data-class"))

So now whenever you add data-class to the popover call, it will add the attribute to the <div class="popover"> div.

Now that I see it, it's so obvious :)

Kate
  • 1,638
  • 1
  • 14
  • 15
18

Its an old post but I'm adding it just as reference. Modifying Shankar Cabus answer, instead of adding the dynamic-class to parent, it will be added in the created .popover div.

$(function(){
    $('a[rel=popover]')
    .popover({
        placement : 'bottom',
        trigger : 'hover'
    })
    .on("hover", function(){
        $('.popover').addClass($(this).data("class")); //Add class .dynamic-class to <div>
    });
});

Hope this helps :)

Community
  • 1
  • 1
Etjie
  • 181
  • 1
  • 3
  • 2
    +1 Instead of hacking the core, which makes it harder to keep the plugin up-to-date, this makes the best of the situation. – Christofer Eliasson Feb 05 '13 at 15:22
  • 4
    I know this is from a long time ago, but just for reference - this is not related to my initial question, so it wouldn't have helped anyway. I wanted separate classes for each separate popover, not one generic class for all the popovers. Hence why I made a new data- element. I can understand how this has helped other people, but it is not related to what I was initially asking. – Kate Nov 11 '13 at 01:52
14

How about adding that class ONLY to appropriate popover, without targeting others?

$('#someElement').popover({placement: function(context, src) {
    $(context).addClass('my-custom-class');
    return 'top'; // - 'top' placement in my case
});

or some variation, like taking custom class name from data of 'someElement', like so:

$('#someElement').popover({placement: function(context, src) {
    $(context).addClass($(src).data('customClassName'));
    return 'top';
});
El Kopyto
  • 1,157
  • 3
  • 18
  • 33
  • if you are trying to set the width of the popover via a css class, i would use this method so the position is compensating the change of width on the popover. (ex, if you are using placement left, your popover might appear on top of your link if you made it wider) – JrBriones Dec 05 '13 at 15:14
  • 4
    I think this is really the simplest and most direct answer without needing to modify the template or use `.tip()`. I like it because it lets me use .popover's `trigger: 'manual'` and thus `.show()` without any other issues. – gdibble Aug 18 '16 at 18:54
  • thank you, this appears to be the best solution to me – lorenzo May 25 '20 at 13:31
11

Just set the hidden "template" option when initializing the tooltip. I don't know why the bootstrap team would keep this a secret...

$(elem).popover({
    template: '<div class="popover YOURCLASS"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
}).popover('show');

Hope this helps...

kdelmonte
  • 680
  • 1
  • 10
  • 16
8

This has been asked a few years ago, and there are plenty of answers. But... I recently had to tackle the same problem myself, and I - (a) wanted to avoid manipulating source code and (b) needed a generic solution to be reused constantly (so using the template: '...' solution for each initialization was out).

My solution was simple enough, and is sort of the same as the marked answer - I figured popover is an extension of the tooltip.js library. I mean - check it out, the source code is barely more than a hundred lines. So I created a file called popover-extend.js, and copy-pasted the entire popover source code in. From there it was easy - simple manipulate these lines:

Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
    // add this:
    cls: ''
});

then:

Popover.prototype.setContent = function () {
    // add this:
    if (this.options.cls) {
        $tip.addClass(this.options.cls);    
    }

Now you can do:

<a href="#" rel="popover" 
   data-cls="dynamic-class" 
   title="Title goes here" data-content="Content goes here">

It's a really good approach if you're like me and want to add more functionality. for example, here's how I added a generic close button to the title (though it requires the popover to have a specified id):

// added this to the the DEFAULTS
close: ''


// added this to the setContent function
if (this.options.close) {
    var id = this.$element.attr('id'),
        btn = $("<button></button>", {
            "class": "close",
            "id": "close",
            "onclick": "$('#"+id+"').popover('hide');"
    }),

    title = $tip.find('.popover-title');

    btn.html("&times;");
    btn.appendTo(title);
}

The cool thing about it, is that everything you set in the DEFAULTS can be configured via html, i.e. if you add a variable named foo, you will be automatically able to manipulate it through data-foo=.

Hope this helps anyone looking for an alternative to manipulating source code

yuvi
  • 18,155
  • 8
  • 56
  • 93
  • 2
    Just want to point out to anyone re-searching for a solution like this; this question of mine was asked back in August 2012 (when we were using Bootstrap version 2.3 I believe). Things have changed..! Thank you for adding a solution for the latest Bootstrap version (3.1.1). – Kate Mar 17 '14 at 01:08
  • This is the best answer on here. It allows you not to break the core library and is not some hack. Sends slightly more to the browser but is worth it. – Tony Jun 13 '14 at 17:01
  • Thanks @Tony. If you want to avoid sending more information to the browser, download [a customized version of bootstrap](http://getbootstrap.com/customize/) without popover.js, and you'll save that expense. Though, admittedly, that would be the same as manipulating the source code – yuvi Jun 13 '14 at 21:46
  • I like this technique the most here, I implemented something very similar. This is the most volatile and elegant solution IMO. – Zoltán Tamási Nov 25 '15 at 13:07
  • This is the best solution. – theringostarrs Apr 27 '16 at 13:21
5

I had the same problem, I liked the answer of @Kate, but changes in the source file can generate so much problems in the future, you probably will forget these little changes when you update your bootstrap's version. So I found another way of doing that:

 $(element).popover({...}).data("popover").tip().addClass("your_class")

As @CorayThan fix it with data("popover")

The method tip() of popover returns the popover element, and creates when it is not created, therefore you will always get the correct popover element, even if you are at the initialization of popover (This is my case =D ).

  • 2
    That didn't work for me. Creating the popover, and then using `$(element).data('popover').tip().addClass("your_class");` did work though. – CorayThan Jul 12 '13 at 19:05
  • Do you try what @CorayThan said? I edited my answer right now with that, I forgot it – Jefferson Henrique C. Soares Aug 23 '13 at 20:26
  • 1
    In recent versions the data key is "bs.popover": `$(element).popover({...}).data("bs.popover").tip()` – mbh Sep 05 '13 at 22:05
  • Hi, I'm getting an undefined error. Can you please have a look. Here is my code http://stackoverflow.com/questions/38495436/typeerror-popover-data-is-undefined?noredirect=1#comment64391351_38495436 – Fazeela Abu Zohra Jul 21 '16 at 08:21
  • Late to the game on this one but am I right in thinking that `.tip()` will not return the popover when used on dynamic elements with the `selector` option? Seems not for me. – shooftie Jan 11 '17 at 17:23
3

It's getting late over here and I'm getting tired but here's a quick one-liner that won't work in the future if you decide to update bootstrap's js files.

Take a look at the bootstrap-tooltip.js file in this gist on line 150.

And here's the modified tooltip in action:

Here's the modified tooltip in action

Checkout the inspector's window down there and you'll notice that the dynamic-class has been added to the tooltip.

I'll post a more long-termable & appropriate answer tomorrow.

bchhun
  • 18,116
  • 8
  • 28
  • 31
  • This is what I'm after, but I am unclear on how to get it implemented. I grabbed the script you linked to and added data-class in hopes it would 'magically' work, but it unfortunately didn't ;) Is there something else I need to do? Just to confirm too, I'm hoping to get it working in the bootstrap popover, not the bootstrap tooltip. – Kate Aug 30 '12 at 04:50
  • After a lot of head scratching, dinner, some TV and more digging through the code, I got it working - and it was based on what you wrote. So thank you! I will be writing the full explanation and labelling it as correct, but I just wanted to thank you for your quick reply. – Kate Aug 30 '12 at 12:44
2

This works for me. It is inspired by the bootstrap's documentation from here, the Events section.

$("a[rel=popover]").popover().on("show.bs.popover", function(){
    $(".popover").addClass("your-custom-class");
});
Marius Ilie
  • 3,283
  • 2
  • 25
  • 27
2

Also you can make use of 'template' options

$element.popover({                               
   html: true,
   trigger: 'click',
   template: '<div class="popover '+MY_CLASS+'" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
   content: function() {
    return 'hello';
   }
});

Update MY_CLASS from you data-class attribute.

Munawer Aziz
  • 196
  • 1
  • 7
2

You could use the container option to get around this.

$('[data-toggle="popover"]').popover({
    container: '#foo'
});

or set it through a tag attribute

<a href="#" data-toggle="popover" data-container="#foo" data-content="Content">Foo</a>

And add this somewhere before closing the body tag

<div id="foo"></div>

Then you could do something like #foo > .popover. I know this is not a one-size-fits-all solution but it's one way to do it.

Hockic
  • 186
  • 1
  • 4
2

I know this thread is old, but for those who stumble across this article as I did, here is another method that will allow more customisation. I haven't tested it with Bootstrap 4 but it with Bootstrap 3.

Instead of hard-coding a class in the function, you can 'submit' a css class to your popover via your html element using a custom data attribute. For this example I've called that attribute "data-class".

As this method exploits the function available to the popovers 'placement' options, I've configured it to preserve the original placement configured in the popover.

jQuery( '[data-toggle="popover"]' ).popover({

    container: 'body',

    placement: function ( popover, trigger ){

        // Get the submitted placement for the popover
        var placement = jQuery( trigger ).attr( 'data-placement' );

        // Get the class(es) to apply to the popover
        var dataClass = jQuery( trigger ).attr( 'data-class' );

        // Apply the submitted class(es) to the popover element
        jQuery( popover).addClass( dataClass );

        // Return the original placement for the popover
        return placement;

        },

        trigger: 'hover'

});

I hope this helps. If anyone has a better or cleaner way of doing this I'd be happy to learn :)

chimerawd
  • 21
  • 2
1

This extend your class from out side bootstrap core class, just add the attribute data-class and an option dataClass: true to your tooltip function

!function($){   
    $.extend($.fn.tooltip.Constructor.DEFAULTS,{
        dataClass: false
    }); 
    var Tooltip = $.fn.tooltip.Constructor;
        _show = Tooltip.prototype.show;

    Tooltip.prototype.show = function (){
        _show.apply(this,Array.prototype.slice.apply(arguments));

        if (this.options.dataClass!=="undefined" && this.options.dataClass){
            var that = this;
            var $tip = this.tip();
            if (this.$element.attr("data-class") !== undefined)
                $tip.addClass(this.$element.attr("data-class"));
        }
    };
}(jQuery);
Abhishek Chaubey
  • 2,960
  • 1
  • 17
  • 24
Nguyen Linh
  • 266
  • 2
  • 8
1

for bootstrap v3.3.2 you find these lines on bootstrap.js

   $tip
    .detach()
    .css({ top: 0, left: 0, display: 'block' })
    .addClass(placement)
    .data('bs.' + this.type, this)

Then you add this line

    .addClass(this.$element.attr("data-class")) 

Now to add a class on your popover element, you will be just putting an attribute data-class="classexemple" then everything works perfect

Find us on www.mixpres.com

Alex Filatov
  • 2,232
  • 3
  • 32
  • 39
1

In Bootstrap 4 you can use the data-template attribute:

<button data-toggle="popover" data-template='<div class="popover MYSUPERCLASS" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' data-offset="-10 0" data-html="true" data-trigger="focus" data-placement="bottom" data-content='My Popover'>Button</button>
Arerrac
  • 409
  • 1
  • 5
  • 18
1
$('a[rel=popover]')
  .popover({ placement: 'bottom', trigger: 'hover' })
  .data('bs.popover')
  .addAttachmentClass('my-own-popover')

You'll get bs-popover-my-own-popover class inside .popover element.

Eugene
  • 492
  • 4
  • 9
1

The best solution for this problem is to extend the popover and built your own version of Popover. Below is the code and it's based on bootstrap version 3.3.7

        (function($){
            var PopoverEx = function(element, options){
                this.init('popover', element, options);
            }

                PopoverEx.prototype = $.extend({}, $.fn.popover.Constructor.prototype, {

                    constructor: PopoverEx,
                    tip: function(){
                        if(!this.$tip){
                            this.$tip = $(this.options.template);
                            if(this.options.modifier) this.$tip.addClass(this.options.modifier);
                        }
                        return this.$tip; 
                    }       
                });

            $.fn.popoverex = function(option){
               return this.each(function () {
                var $this   = $(this)
                var data    = $this.data('bs.popover')
                var options = typeof option == 'object' && option

                if (!data && /destroy|hide/.test(option)) return
                if (!data) $this.data('bs.popover', (data = new PopoverEx(this, options)))
                if (typeof option == 'string') data[option]()
              })
            }
        })(window.jQuery);

Usage

HTML Code

    <a href="#" class="btn btn-large btn-danger" 
          rel="popover" 
          data-modifier="popover-info" 
          title="A Title" 
          data-content="And here's some amazing content.right?">Hover for popover</a>   

JS script

    jQuery(document).ready(function($) {
        $('[rel="popover"]').popoverex();
    });

You will find full version and description from this git page https://gist.github.com/vinoddC/475669d94e97f4d7b6bcfde4cef80420

It's a updated version of Brian Woodward's work.

0

Sorry, but did not quite understand your question ... But what you want is to add a parent div? Take it easy ... See if this is what you want:

$(function(){
    $('a[rel=popover]')
    .popover({
        placement : 'bottom',
        trigger : 'hover'
    })
    .on("click", function(){
        $(this).closest("div").addClass($(this).data("class")); //Add class .dynamic-class to <div>
    });
});

Demo: http://jsfiddle.net/PRQfJ/

Shankar Cabus
  • 9,302
  • 7
  • 33
  • 43
  • Not exactly correct - I'm not wanting to add a _new_ `
    `, but **an additional**, new, dynamic class to the `
    `. Does that make sense?
    – Kate Aug 30 '12 at 04:58
0

best option that works on every vesion of BS, is to make it inside a specefic class and after showing that, find that class, and add your classname to popover parrent of it

// create a template that add the message inside
var $tmp = $("<div class='popoperrormessage'>" + error + "</div>");


            $(this).popover("destroy").popover({
                trigger: "manual",
                animation: false,
                html: true,
                placement:"right",
                content: $tmp,
                container: "body"
            }).popover("show");


            // now we have to find the parent of the popoperrormessagemessage
            $(".popoperrormessage").parents(".popover").addClass("hello");

Now your popover will have hello class

Ata
  • 12,126
  • 19
  • 63
  • 97
0

Here is my workaround, probably not the most efficient but I found it the easiest to implement.

 $('[data-content]').each(function(){
    var options = {
        html: true //optional
    };

    if ($(this)[0].hasAttribute('data-class')) {
        options['template'] = '<div class="popover" role="tooltip ' + $(this).attr('data-class') + '"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>';
    }

    $(this).popover(options);
});

Just add data-class="custom-class" to the element like the other examples.

Pat Migliaccio
  • 1,031
  • 13
  • 24
-1

I'm not sure why you want to do this, but in my example, I just wanted to set custom style... So in CSS just written right selector for current popover. a.rating-popover - this is my link for opening popover. -> the popover element will be generated to the next of that element. so we can select it with

a.rating-popover + div.popover{
   background: blue;
}

and voila, blue background. for only popovers opened with a.rating-popover element.

Mesrop
  • 17
  • 2
  • Because I was generating the popover dynamically, so the popover was at the bottom of the `` - not the adjacent selector. – Kate May 02 '13 at 04:44