erichynds

Hi, I'm Eric Hynds, a front-end website developer living outside of Boston, Massachusetts. I'm passionate about developing functional, standard-compliant, and user-friendly websites.

A jQuery UI Growl/Ubuntu-like Notification Widget

Update 7/6/2010: version 1.4.1 is out!

There are about a dozen other plugins out there that do this already, except most seem to come with an enormous footprint: 10-12k of code, X-number of images, and roughly 1000 options to support every plausible use case. For other minimalists like myself out there, here’s one built off the jQuery UI widget factory in approx. 110 lines of code and 100% CSS. In typical widget fashion, this implementation supports the most basic (and arguably most common) uses, but is flexible enough for more advanced cases.

Internet Explorer is a big-time downer with no HSLA/border-radius/box-shadow support, so if eye candy is important to you in IE, a transparent png background or similar can be added without much effort.

Usage

Using this widget is a simple four step process:

Step 1:

Include the JavaScript and CSS dependencies. Only the widget factory from jQuery UI is required.

  1. CSS file: ui.notify.css
  2. jQuery and the jQuery UI widget factory: ui.widget.js
  3. This widget: ui.notify.js

Step 2:

Create a container element to hold notifications, and a template from which all notifications will be constructed from. With this, you can have multiple containers on the same page holding different styles of notifications. Each container can contain different templates.

<!-- set the container hidden to avoid a flash of unstyled content
when the page first loads -->
<div id="container" style="display:none">
 
    <!-- 
    Later on, you can choose which template to use by referring to the 
    ID assigned to each template.  Alternatively, you could refer
    to each template by index, so in this example, "basic-tempate" is
    index 0 and "advanced-template" is index 1.
    -->
    <div id="basic-template">
        <a class="ui-notify-cross ui-notify-close" href="#">x</a>
        <h1>#{title}</h1>
        <p>#{text}</p>
    </div>
 
    <div id="advanced-template">
        <!-- ... you get the idea ... -->
    </div>
 
</div>

Once the widget is initialized on the container, each template is cached and removed from the DOM. You can add one or more close links in your template by assigning each anchor the class ui-notify-close. The close link in this example has additional styling through the class ui-notify-cross, which makes the “x” look like an icon.

Define any variables you want to include in this template using #{varname} syntax. You can call these anything you’d like.

Step 3

Initiate the widget on the container, optionally passing in a hash of default options:

// basic
$("#container").notify();
 
// or with options (there are only 2)
$("#container").notify({
    speed: 500,
    expires: false
});

Step 4

Notifications are actually displayed by calling the create method. Pass in an hash of variables to transpose into the template:

// notice the templates in step 2 are expecting title and text variables.
// you can add as many as you like, and call them whatever you want.
$("#container").notify("create", {
    title: 'Test Notification',
    text: 'This is an example of the default config, and will fade out after five seconds.'
});

If you’d like, set specific options for each notification by passing in a second hash:

// example of overriding the expires and speed options for one notification
$("#container").notify("create", {
    title: 'Test Notification',
    text: 'This is an example of the default config, and will fade out after five seconds.'
},{
    expires: false,
    speed: 1000
});

You can specify the template to use by passing in the ID of the template as the second parameter. This is optional, and if not provided the first template defined will be used. Alternatively, you can pass in the index of the template in the container as the second argument.

// create a new notification using the "basic" template
// that we defined in step 2.
$("#container").notify("create", "basic-template", { /* template vars */ });
 
// we can refer to the template by index as well.  this
// statement is equivalent:
$("#container").notify("create", 0, { /* template vars */ });

The create method returns a notification instance object with two public methods: open and close.

// create a new "sticky" notification
var instance = $("#container").notify("create", {}, { sticky:true });
 
// close it
instance.close();
 
// re-open it
instance.open();

Options

These options can be set for all notifications within a container, or on a notification-by-notification basis:

Parameter Description Default
speed The amount of time in milliseconds to fade notifications in and out. 500
expires Notifications will automatically close after this amount of time, in milliseconds. Set to 0 or false to create a “sticky” notifications. 5000
stack

New in version 1.2.1!

Notifications will stack downwards if set to “below” (default), or upwards if set to “above.”

below
custom
New in version 1.3!

A boolean value denoting whether or not the widget should apply its own styling classes. Set to false to roll your own notification themes (including ThemeRoller). You could simply overwrite the included CSS, but using this option allows you to create default AND custom notifications within the same containers, as well as maintain a clear upgrade path as you won’t have to touch any of the included files.

false

Events

These events can be bound by passing handlers in as options. Example:

// for a specific notification
$("#example").notify("create", { /* template vars */ },{
   open: function(){
      alert("Notification opened!");
   }
});
 
// or for all notifications within a container
$("#container").notify({
   open: function(){
      alert("Notification opened!");
   }
});
Event Description
beforeopen Fires before the notification opens. If false is returned inside this callback, the notification will not open.
open Fires after the notifcation opens.
close Fires after the notifcation closes.
click Fires if the user clicks anywhere in the notification itself (not on the close link(s), if present). Useful if you want to close the notification or perform some other action once the user has acknowledged the notice. The callback receives two parameters as arguments: the event object, and the notification instance object.

Example:

$("#container").notify("create", {
   title: 'Clickable Notification',
   text: 'Click on me to fire a callback'
},{
   click: function(e,instance){
      // close the notice if the user clicks anywhere inside it
      instance.close();
   }
});

FAQ

How do I use ThemeRoller in my templates?

First, create a template and apply the appropriate ThemeRoller classes, icon classes you want to use, etc.:

<div id="notification-container">
 
   <div id="themeroller" class="ui-state-error">
      <!-- close link -->
      <a class="ui-notify-close" href="#">
         <span class="ui-icon ui-icon-close" style="float:right"></span>
      </a>
 
      <!-- alert icon -->
      <span style="float:left; margin:2px 5px 0 0;" class="ui-icon ui-icon-alert"></span>
 
      <h1>#{title}</h1>
      <p>#{text}</p>
   </div>
 
   <!-- other templates here, if you'd like.. -->
</div>

Next, either when you init the widget or create a notification, ensure the custom parameter is set to false:

// prevent notify from imposing its own styling classes
// on ALL notifications inside this container 
var handler = $("#notification-container")
      .notify({ custom:true })
      .notify("create", { title:"foo", text:"bar" });
 
// or just themeroller templates
var handler = $("#notification-container")
      .notify()
      .notify("create", "themeroller", { title:"foo", text:"bar" }, { custom:true };

How do I add a close icon or link to my templates?

Any link, button, etc. with the class ui-notify-close will close the notification when clicked. To use the X close link as seen in the demos, apply the ui-notify-cross class as well:

<a class="ui-notify-close ui-notify-cross" href="#">x</a>

How do I avoid a FOUC (flash of unstyled content) when the page first loads?

Simply give your container the display: none; CSS property. Once you initialize this widget on the container, it’ll take care of the rest.

Related posts:

  1. Using $.widget.bridge Outside of the Widget Factory
  2. jQuery UI MultiSelect Widget
  3. Tips for Developing jQuery UI 1.8 Widgets

Tags: , , , ,

  • http://twitter.com/awenkhh Andreas Wenk

    if you like Mac's Growl check this jQuery plugin out – really nice

  • http://www.heavyworks.net Jan Seidl

    This is a really great plugin. I love this kind of notifications!

    Congrats for the job! Suggestions if you permit:

    - Enable prompt() like notifications (Yes/no)
    - Enable alternate positionings (top-left, top-center, bottom-left etc etc)
    - Templates (groupings of positioning/type configurations)

    Keep up the good work, I have a good JS knowlegde, let me know if you need some help.
    I'm on github too.

  • http://twitter.com/davidmh Chuck

    did you inspire in $.growlUI from jQuery BlockUI to make this plugin?

    http://jquery.malsup.com/block/#demos

  • ehynds

    @Jan, thanks. fork it up :)

    @Chuck very cool! Had not seen that. I was looking for something simple and lightweight on the widget factory, and decided to roll my own.

  • http://www.deluxeblogtips.com/ Rilwis

    It's cool. I'm using Ubuntu, and when I launch the demo, I don't realize where's the Ubuntu's notification and where's yours. Very nice effect. Thanks for sharing.

  • http://twitter.com/teenDev Alex Bailey

    Wow! Great stuff. Don't know if you noticed that your DISQUS logins don't work or at least they didn't for me.

  • http://twitter.com/evantbyrne Evan Byrne

    This would be perfect for a project of mine if i could get it to load the notifications from the bottom right. Great job Eric!

  • http://twitter.com/evantbyrne Evan Byrne

    This would be perfect for a project of mine if i could get it to load the notifications from the bottom right. Great job Eric!

  • ehynds

    Evan, I just added a “position” option. Place the container on the bottom of the screen (position:absolute; bottom:0), and set the “position” option to “above”. See the updated demo page for more examples.

  • Aozora

    It would be perfect if it will integrate with jQuery UI ThemeRoller!

  • http://www.jebaird.com/ jebaird

    Hey Eric, This widget is pretty slick. I just forked and committed a version on github, that adds ThemeRoller support, passing templates through the options, 3 predefined templates, default, error, and highlight so it works “out of the box”. Also I added the defaultTemplate option and rearranged the order of the arguments for the create method due to the default template option

    Please let me know what you think of my changes. Thanks for sharing this awesome piece of code.

  • htrex

    your useful lib fails to replace variables in src and href attributes.
    I haven't checked yet with every browser but in FF and think
    that's normal, because { and } characters are not allowed in URLs and are replaced by the browser with %7B and %7D respectively.
    to make it work also there you should replace your regex with /#(?:{|%7B)(.*?)(?:}|%7D)/g

  • Pablo

    Well, this is great, i'm new with CSS & javascript, I was testing this plugin and I have a question, how can I call create function from HTML? using

    <script type=”text/javascript”>
    create(undefined, { title:'Default Notification', text:'Example of a default notification.'});
    </script>
    simply does not work,

    in a link <a href=”#” onClick=”javascript:create(params)”>Link works perfectly
    I only want to show a notification after inserting a register into mysql database from php, thanks in advance.

    Pablo

  • ehynds

    great catch – thanks a lot. I just committed this new regex.

  • ehynds

    You need to call create on your container: $(“#container”).notify(“create”, { title: 'default', text: 'example' })

  • ehynds

    Awesome jebaird. I love the “cross” close icon in there from themeroller and the error/success classes. nice work!

  • http://www.jebaird.com/ jebaird

    I forked a version on github that integrates jQuery UI ThemeRoller you should check it out – http://github.com/jebaird/jquery-notify

  • Pablo

    Thanks again, it works perfectly.

  • http://www.jebaird.com/ jebaird

    I forked a version on github that integrates jQuery UI ThemeRoller you should check it out – http://github.com/jebaird/jquery-notify

  • Pablo

    Thanks again, it works perfectly.

  • Adrian

    I cannot get beforeOpen event to fire. I have already defined the default options for the parent container, but am trying to overwrite for the beforeOpen for a child. Is this a known bug

  • Adrian

    Sorry let me correct it. I can't get beforeOpen to fire period. I'm testing in firebug

    var $container = jQuery('#notifications').notify({
    expires: 5000,
    open:function(e, instance){
    jQuery(this).effect('bounce');
    },
    speed: 1200,
    stack:'above',
    click:function(e, instance){
    instance.close();
    },
    beforeOpen:function(e, instance){
    jQuery(this).addClass('systemError');
    }
    });

  • ehynds

    Hi Adrian,

    I actually did find a bug while testing this out, but only when binding to the “notifybeforeopen” event, not when passing a handler in the options which is what you're trying to do. Rename “beforeOpen” to “beforeopen” (all lowercase) and see if that doesn't fix it.

    I've put a test together so you can see the events are working correctly: http://jsfiddle.net/866C9/

  • http://twitter.com/metalculus84 Adrian Adkison

    Don't be fooled by new face, it's Adrian. All lowercase solved the problem! Thanks so much for your help and for developing this awesome widget!

  • http://twitter.com/thechozenfew Pablo

    I was trying to keep the close button on a regular notification but it seems that the widget itself deletes the close button class.

    Does anyone has a work around for this?
    I would like to be able set a notification to auto fadeout and also give the user to close it.

  • http://twitter.com/metalculus84 Adrian Adkison

    This is not a solution, but for your first inquiry I think if the sticky property is set to false, the widget will not display the close button.

    As for the second, set an expires time and set the click function to like Eric has done above.
    click:function(e, instance){
    instance.close();
    }

    So i guess a solution would be to set:
    sticky: false,
    click:function(e, instance){
    instance.close();
    }

  • http://twitter.com/thechozenfew Pablo

    i came with a solution where i can keep the close button and have the auto fadeout effect in the widget as well, using some global variables.

    Maybe not the best solution but it works, here is the function and the globals:
    The pretty print code link: http://pastie.org/989866 *code block are broken when pasted here directly

    If you took a look the code here are some examples:

    Creates a sticky note that fadesout after 5 seconds
    create(false,{title: “Hello World”})

    Creates a sticky note that fadesout after 10 seconds
    create(false,{title: “Hello World”},10)

    Creates a REAL sticky note that won't fadeout automatically
    create(false,{title: “Hello World”},0)

  • ehynds

    Yeah, i hide the close link if the notification isn't “sticky” because I personally don't see a need for it. The notification will close itself and is how Ubuntu/Growl works.

    You guys tell me – does it make sense to have another option labeled “showCloseIcon” or something to the effect?

  • http://twitter.com/thechozenfew Pablo

    Thanks for the great widget man, is just what i needed , this should be included in the jquery UI widgets.

    One question, can i do some minor modifications to the widget? i just want to edit the animation effects for my own use.

  • ehynds

    Sure, do whatever you'd like!

  • ehynds

    Sure, do whatever you'd like!

  • ehynds

    Hi folks,

    I released 1.3 this morning, which includes an option that will prevent notify from applying it's own styling class. With this, you can truly customize the notifications however you'd like, including applying ThemeRoller classes.

    See the updated demos for an example of ThemeRoller-styled notifications, and read the (new) FAQ section on how to set it up.

    Thanks!

  • ehynds

    Hi folks,

    I released 1.3 this morning, which includes an option that will prevent notify from applying it's own styling class. With this, you can truly customize the notifications however you'd like, including applying ThemeRoller classes.

    See the updated demos for an example of ThemeRoller-styled notifications, and read the (new) FAQ section on how to set it up.

    Thanks!

  • Dave Forster

    I'm liking this a lot but have noticed an issue with this in Internet Explorer (surprise surprise). On page load the “Container” div and it's contents can be seen initially before the widget initialises i.e. it flickers. This behaviour isn't present in FF. Is there a work around ?

  • ehynds

    Hi Dave, thanks for the comment. I released version 1.4 this morning to address this issue… just make sure your container is set to display:none; and you'll be all set.

  • Dave Forster

    Great stuff.. cheers

  • http://ilovebonnie.net ilovebonnie.net

    In your example where you are using an image in your template, you use src=”#{icon}” — this is not a good way to handle this. If you examine the page and your requests/logs, you'll notice that a tag like that will cause the server to make an additional request to the page like: http://example.com/#{icon}. This is no bueno. The way to alleviate this is to, instead, do #{icon} for the entire image tag and then replace it with <img src=”/images/imagesrc.jpg”> instead of just replacing the src attribute.

  • Guest

    Did you submit your plug-in to the jQuery UI Team ? I can't see anything related with it :(

  • http://cdnpic.com cdnpic

    nice.we can create notifications in ubuntu using lib-notify ;)

  • ehynds

    have not. to be honest, I'm too lazy/busy to draw up a spec for their wiki :)

  • ehynds

    no bueno indeed. I shall fix.. thx for the heads up.

  • Guest

    Well if you are ok, i might have some time during the first week of August.
    May be i could improve the plugin by making it more compliant with ThemRoller, more modular, and add some functionnalities inspired by this plugin : http://www.stanlemon.net/projects/jgrowl.html
    And submit it.

  • Chimpski

    I'm having issues with IE7 and this plugin the demo seems to work in IE7 but I can't seem to get 1.4 to work. Is this an issue fixed in 1.4.1? The div is showing up left aligned inside the page instead of on top of it in the right top corner. Any ideas what I'm doing wrong?

  • ehynds

    1.4.1 changes the positioning to fixed instead of absolute, which may very well solve your issue. give it a try.

  • Cratig

    Hi,

    I have a small issue with this plugin – in IE 8 (Windows XP) leaving the container div without any styles attached I can see the templates.

    If I, using stylesheet, use display: none; on the container div then I cannot see any popups – even in Firefox.

    Any ideas?

    Thanks

  • Veerugadde

    Hey Eric,

    Trying to use this notification plugin in such way, only open if a condition is met. So i’m using before open to check if that is condition and if not it should not open.But in both ways it open the notification.Can you please how do i need to resolve that?

    here is the code i tried:

    function create( template, vars, opts ){
    return $container.notify(“create”, template, vars, opts);
    }

    $(function(){
    // initialize widget on a container, passing in all the defaults.
    // the defaults will apply to any notification created within this
    // container, but can be overwritten on notification-by-notification
    // basis.
    $container = $(“#container”).notify();

    create(“sticky”,{ title:’Sticky Notification’, text:’There is an approval pending for more than one week. Click on the X above to close me.’}, {
    beforeopen: function(){
    $.post(“ajax.php”, {“function”:”urgentApproval”}, function(data){
    if (data == “true”) {
    return true;
    }

    }, ‘html’);
    }
    });

    });

  • http://twitter.com/c_schmitz Carsten Schmitz

    I am getting this too. Did you find a solution?

  • Anonymous

    are you guys calling notify() before attempting to create? I have it working fine with default config here: http://jsfiddle.net/dJpcT/

  • http://www.cwinters.com/ Chris Winters

    Nice work! Have you looked into using the built-in jQuery templating rather than your own? http://api.jquery.com/category/plugins/templates/

  • http://profiles.google.com/shawn.milo Shawn Milochik

    I had this problem today; turned out to be 100% due to my versions of jQuery and jQuery UI. Note the requirements in the header of the .js include.

  • http://profiles.google.com/massimiliano.dellarovere Massimiliano della Rovere

    It would be nice to have a parameter to set the z-index property of the messages. I use jquery-ui buttons and jqgrid tables a lot and they set their z-index bigger than that of notifications ;-)

  • ashok raavi

    If there are multiple sticky notifications open, how to close all the notifications at once instead of clicking on ‘x’ for each notification.

  • Petr Braha

    How can I disable moving up newer notifications after I close previous? I have them dropable and I am moving them on whole page, but when I close old one, newer will move up (even out of screen).

  • Petr Braha

    How can I disable moving up newer notifications after I close previous? I have them dropable and I am moving them on whole page, but when I close old one, newer will move up (even out of screen).

  • Sikrip

    Awesome widget!

  • Anonymous

    Great plugin! 

    However, I am having an issue in selecting the template index ID as a parameter. I’m using a variable to assign it a number, but it seems that only 0 (the default) works. I have multiple templates listed in the container div, but apparently only the default one works. Any help?

  • Anil S

    Awesome plugin. I am going to integrate this with ZK framework in one of my projects.