bubbletip! A jQuery Coda-style bubble tooltip plugin

Download

http://code.google.com/p/bubbletip/downloads/list

Demo page

http://uhleeka.com/demo/bubbletip/

Discuss

http://groups.google.com/group/bubbletip

Features

  • multiple tips on a page
  • multiple tips per jQuery element
  • tips open outward in four directions:
    • up
    • down
    • left
    • right
  • tips can be:
    • anchored to the triggering jQuery element
    • absolutely positioned
    • opened at the current mouse coordinates
    • anchored to a specified jQuery element
  • IE png transparency is handled via filters

Tested (lightly)

  • IE 6 on XP
  • IE 7 and 8 on Vista
  • Firefox 3.5 on Vista
  • Chrome 3.0 on Vista
  • Safari 3.2 on Vista

Examples

MOUSEOVER to open a tooltip above, below, to the left or to the right of any element.

MOUSEOVER a trigger element to open a tooltip above and below a target element.


Using it?

If you enjoy using it, I’d love to hear about it. Drop a comment with a link!

Credit

bubbletip was inspired by http://jqueryfordesigners.com/coda-popup-bubbles/.

100 Comments

  1. I was hoping you could help me. I have a table with a link in each row. After each link, I have a <div class="popup">Unique popup text</div>. I am hiding all popups with simple css: .popup { display:none; }

    I have been using aqLayer plugin to show the popups when someone hovers over the links using the following code:

    $('#mytable td.url').hover(
    function() {
    $(this).aqLayer({ opacity: 1, layerCss: {…} });
    $(this).aqLayer( $(this).children('.popup').html() );
    },
    function() {
    $(this).aqLayer('hide');
    }
    );

    And now I am trying to do the same thing using the BubbleTip, but is looks like it's not working with any popup that does not have a unique ID assigned to it. Here is the code I am trying to use:

    $('#mytable td.url').hover(
    function() {
    $(this).bubbletip($(this).children('.popup').html(), { deltaDirection:'right' } );
    },
    function() {
    $(this).removeBubbletip();
    }
    );

    If I replace $(this).children('.popup').html() with $('#tip1'), which is a dummy popup with id tip1, then the code works and is showing this dummy popup for all the links in the table. Am I missing something or is there no way to display popups that don't have an id assigned? Is there maybe a workaround?

  2. I am wondering if it is possible to have/fake dynamic positioning? I would like the bubbletip to default to down (easy enough) but if the triggering content is at the bottom of the page then pop up instead of down so that the bubble tip is still on the page. Pop to the left if the content is too far right and pop right if the content is too far the the left. Having the bubbletip partially off of the page is not ideal.

    The site is still in development so I don't have a URL for you.

    Thanks
    -Cam

  3. I had posted yesterday about having the bubbletip be dynamically placed. I have been tinkering with it and have come up with part of the solution. Thought I would pass it along in case you were interested.

    replaced:
    /* create the wrapper table element
    if (_options.deltaDirection.match(/^up$/i)) {
    _wrapper = $('<table class="bubbletip" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td class="bt-top"></td><td class="bt-topright"></td></tr><tr><td class="bt-left"></td><td class="bt-content"></td><td class="bt-right"></td></tr><tr><td class="bt-bottomleft"></td><td><table class="bt-bottom" cellspacing="0" cellpadding="0"><tr><th></th><td><div></div></td><th></th></tr></table></td><td class="bt-bottomright"></td></tr></tbody></table>');
    } else if (_options.deltaDirection.match(/^down$/i)) {
    _wrapper = $('<table class="bubbletip" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td><table class="bt-top" cellspacing="0" cellpadding="0"><tr><th class="left"></th><td><div></div></td><th class="right"></th></tr></table></td><td class="bt-topright"></td></tr><tr><td class="bt-left"></td><td class="bt-content"></td><td class="bt-right"></td></tr><tr><td class="bt-bottomleft"></td><td class="bt-bottom"></td><td class="bt-bottomright"></td></tr></tbody></table>');
    } else if (_options.deltaDirection.match(/^left$/i)) {
    _wrapper = $('<table class="bubbletip" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td class="bt-top"></td><td class="bt-topright"></td></tr><tr><td class="bt-left"></td><td class="bt-content"></td><td class="bt-right-tail"><div class="bt-right"></div><div class="bt-right-tail"></div><div class="bt-right"></div></td></tr><tr><td class="bt-bottomleft"></td><td class="bt-bottom"></td><td class="bt-bottomright"></td></tr></tbody></table>');
    } else if (_options.deltaDirection.match(/^right$/i)) {
    _wrapper = $('<table class="bubbletip" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td class="bt-top"></td><td class="bt-topright"></td></tr><tr><td class="bt-left-tail"><div class="bt-left"></div><div class="bt-left-tail"></div><div class="bt-left"></div></td><td class="bt-content"></td><td class="bt-right"></td></tr><tr><td class="bt-bottomleft"></td><td class="bt-bottom"></td><td class="bt-bottomright"></td></tr></tbody></table>');
    }

    with:
    // unified HTML blob
    _wrapper = $('<table class="bubbletip btDir-' + _options.deltaDirection + '" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td class="bt-top"></td><td class="dirDown"><table class="bt-top" cellspacing="0" cellpadding="0"><tr><th class="left"></th><td><div></div></td><th class="right"></th></tr></table></td><td class="bt-topright"></td></tr><tr><td class="bt-left"></td><td class="bt-left-tail dirRight"><div class="bt-left"></div><div class="bt-left-tail"></div><div class="bt-left"></div></td><td class="bt-content"></td><td class="bt-right"></td><td class="bt-right-tail dirLeft"><div class="bt-right"></div><div class="bt-right-tail"></div><div class="bt-right"></div></td></tr><tr><td class="bt-bottomleft"></td><td class="bt-bottom"></td><td class="dirUp"><table class="bt-bottom" cellspacing="0" cellpadding="0"><tr><th class="left"></th><td><div></div></td><th class="right"></th></tr></table></td><td class="bt-bottomright"></td></tr></tbody></table>');

    This contains all of the differences between each direction that the bubble tip can be placed in a single blob. It also adds the direction as part of the CSS in the blob.

    The CCS file (sorry it is my working copy so it has other changes in here as well)

    /*******************************/
    /********* bubbletip ***********/
    /*******************************/
    .bubbletip
    {
    position: absolute;
    z-index: 50;
    border-collapse: collapse;
    }
    .bubbletip td.bt-topleft
    {
    background: transparent url(bubbletip.png) no-repeat scroll 0px 0px;
    height: 33px;
    width: 33px;
    }
    .bubbletip td.bt-top
    {
    background: transparent url(bubbletip-T-B.png) repeat-x scroll 0px 0px;
    height: 33px;
    }
    .bubbletip td.bt-topright
    {
    background: transparent url(bubbletip.png) no-repeat scroll -73px 0px;
    height: 33px;
    width: 33px;
    }
    .bubbletip td.bt-left-tail div.bt-left, .bubbletip td.bt-left
    {
    background: transparent url(bubbletip-L-R.png) repeat-y scroll 0px 0px;
    width: 33px;
    }
    .bubbletip td.bt-left-tail div.bt-left-tail
    {
    background: transparent url(bubbletip.png) no-repeat scroll 0px -33px;
    width: 33px;
    height: 40px;
    }
    .bubbletip td.bt-right-tail div.bt-right, .bubbletip td.bt-right
    {
    background: transparent url(bubbletip-L-R.png) repeat-y scroll -33px 0px;
    width: 33px;
    }
    .bubbletip td.bt-right-tail div.bt-right-tail
    {
    background: transparent url(bubbletip.png) no-repeat scroll -73px -33px;
    width: 33px;
    height: 40px;
    }
    .bubbletip td.bt-bottomleft
    {
    background: transparent url(bubbletip.png) no-repeat scroll 0px -73px;
    height: 33px;
    width: 33px;
    }
    .bubbletip td.bt-bottom
    {
    background: transparent url(bubbletip-T-B.png) repeat-x scroll 0px -33px;
    height: 33px;
    }
    .bubbletip td.bt-bottomright
    {
    background: transparent url(bubbletip.png) no-repeat scroll -73px -73px;
    height: 33px;
    width: 33px;
    }
    .bubbletip table.bt-top, .bubbletip table.bt-bottom
    {
    width: 100%;
    }
    .bubbletip table.bt-top th.left
    {
    width: 10px;
    }
    .bubbletip table.bt-top th.right
    {
    width: 90%;
    }
    .bubbletip table.bt-top th
    {
    background: transparent url(bubbletip-T-B.png) repeat-x scroll 0px 0px;
    height: 33px;
    }
    .bubbletip table.bt-bottom th
    {
    background: transparent url(bubbletip-T-B.png) repeat-x scroll 0px -33px;
    }
    .bubbletip table.bt-bottom th.left
    {
    width: 10px;
    }
    .bubbletip table.bt-bottom th.right
    {
    width: 90%;
    }
    .bubbletip table.bt-top td div
    {
    background: transparent url(bubbletip.png) no-repeat scroll -33px 0px;
    width: 40px;
    height: 33px;
    }
    .bubbletip table.bt-bottom td div
    {
    background: transparent url(bubbletip.png) no-repeat scroll -33px -73px;
    width: 40px;
    height: 33px;
    }
    .bubbletip td.bt-content
    {
    background-color: #fff;
    vertical-align: middle;
    }
    /*******************************/
    /*** unified html ***/
    /*******************************/
    .dirDown, .dirUp, .dirRight, .dirLeft
    {
    display: none;
    }
    .btDir-down .dirDown,
    .btDir-up .dirUp,
    .btDir-right .dirRight,
    .btDir-left .dirLeft
    {
    display: block;
    }
    .btDir-down td.bt-top,
    .btDir-right td.bt-left,
    .btDir-left td.bt-right,
    .btDir-up td.bt-bottom
    {
    display: none;
    }

    /*******************************/

    As you can see the CSS hides the bits and pieces that are not needed depending on the directionality of the bubbletip (as determined by the additional CSS class on the bubbletip wrapper).

    I then set 'calculateOnShow' on and hacked on the _Calculate() function. The _Calculate function will do its thing, if the bubble is off the page then it will change the direction and re-call itself. Which causes the bubbletip to appear on the page.I am still tweaking this function. I can send it along once it is done.

    Let me know if you are interested in this code and I will send it by email or something – a blog doesn't seem like the right forum to be sending big slabs-o-text around with.

    -Cam

  4. hi uhleeka, great job on the code, it's very helpful.

    i'm running into a strange issue where the first time i load my test page, all of the positioning is off by around 300px down and right. the problem persists if i reload, but if i click on my name (which just links back to the same page), the problem disappears. any thoughts? i've seen it happen on both firefox and safari. the link is http://www.justinlau.ca/bubbletest.html

    thanks!
    -justin

    • @Justin: try setting the bubbletips in a $(window).bind('load', function() {}); instead of the $(document).ready. Seems like the positioning might be due to the page not rendering completely prior to the tip positions being calculated. alternatively, you could set the { calculateOnShow: true } option.

  5. Sorry about taking a couple of months to reply, I had a massive PC fail!

    I have created a demo of what I am seeing which can be found at http://www.jprestwood.plus.com/bubble/ you want to mouseover the cells that have the red triangle on :)

    I have noticed that IE 7/8 seem to render it fine and put the popup in the right place (as long as calculateOnShow:true is set), FF3.6 renders it in the right place but shows half the box, FF3.5/Opera/Chrome all show the box in the wrong position, just like what Justin is reporting but I see it up and right and mousing over a few times sometimes will put it in the right place, for that time only.

    Thanks for your help :)

    • @James: Hey James, i had already stumbled on the positioning problem you described. the code was using _wrapper.width() and .height() instead of .outerWidth() and .outerHeight(), so the margin/padding was not being factored in when positioning the tips.

      regarding the FF3.6 issue, it seems like an erroneous change on Mozilla's part, but the hack to fix it was as simple as setting the width and height on the _wrapper:

      _wrapper.css({ 'width': _wrapper.width(), 'height': _wrapper.height()});

      it doesn't make sense why FF3.6 requires that, but oh well.

      i posted an update @ http://code.google.com/p/bubbletip/

      thanks!

  6. Hi uhleeka, thanks for the great script. My problem is regarding when Bubbletip is inside a dynamic loop. Here's my code snippet:

    $(document).ready(function() {
    $('img[id^=Tooltip]').bubbletip($('#Tooltip_Content_'+$(this).attr('name')));
    });

    Inside a while loop…
    <div id="Tooltip_Content_<?= $row['id'] ?>" style="display:none;"><?= $row['value'] ?></div>

    And…
    <img src="icon.gif" id="Tooltip_<?= $row['id'] ?>" name="<?= $row['id'] ?>" />

    The JS error that I'm getting is:
    $(tip).get(0) is undefined

    Am I missing something very obvious here?
    Thanks for your time.

    • @Sunny: your use of $(this) is not going to work:

      $('img[id^=Tooltip]').bubbletip($('#Tooltip_Content_'+$(this).attr('name')));

      instead, you need to get $(this) pointing to your <img>:

      $('img[id^=Tooltip]').each(function(i) {
      $(this).bubbletip($('#Tooltip_Content_'+$(this).attr('name')));
      });

      hope that helps!

  7. Hi, really great plugin. I tried more than thousand of similar plugins, but this is the only one which is able to do what I need. But I have found one little problem: Is there way to add one div to be shown by multiple triggers? When I create one tipDiv for each trigger everything is ok but when I'm trying to use same div for multiple triggers the only first one is working.
    P.S. I'm sorry for my English.

    • @Vojta: create your bubble tip on one div, then trigger your bindShow and bindHide events from your other div's.

      $('#myBubbleTipDiv').bubbletip($('#myTip'));
      $('.myOtherDivs').bind('mouseover', function() { $('#myBubbleTipDiv').trigger('mouseover'); });
      $('.myOtherDivs').bind('mouseout', function() { $('#myBubbleTipDiv').trigger('mouseout'); });

      hope that helps!

  8. @uhleeka, re: $(this) pointing to your <img>. Opps! Yeah, that did the trick. Thanks again!

  9. @uhleeka: Thanks, it works. But there it works perfectly in only one version of configuration and in Firefox. In the other ways is problem: there are more events able to hide same Tip and event from the other trigger often hide Tip before it should be hidden by event on trigger which showed it. I have tried change hiding event to mouseleave, but fact that mouse never was on the trigger isn't problem and event is called anyway. It isn't serious problem and I can use it this way, but I think it will be better to ask if I'm not missing something obvious again :)

  10. Pingback: bubbletip- A jQuery Coda-style bubble tooltip plugin | jQuery Wisdom

  11. Pingback: Fix Jquery Error Bubbles Windows XP, Vista, 7, 8 [Solved]

Comments are closed.