Tuesday, August 9, 2011

jQuery UI Icon Buttons

The jQuery UI button widget is flexible in that it can have several different configurations.  They can display text only, icon only, or a combination of the two.  This setup works with either a button or an anchor as the underlying element.  So right out of the box, the button widget is flexible enough to use more than one HTML element type.

One thing the button can't do without modification is display as an icon — without the other theme attributes like the border and background styles.  So if you want a button that only displays as an icon, maybe for a help button placed beside a text input, you've no choice but to alter the button.  An alternative is to extend the theme — to directly modify the theme to not display the border or background styles for button widgets. 

Let's look at an example.  Suppose we want a help button beside a text input — to tell the user what the input is for should they want to know.  When clicked, this button might display the contextual help in a dialog or expand some otherwise closed HTML content.  To do so with a regular button, we might implement the following HTML...

<body>
    <div>
        <input type="text"/>
        <button id="regular_button" title="Help">Help</button>
    </div>
</body>

And here is the Javascript used to instantiate the button widget, passing it a primary icon argument...

$(document).ready(function(){
    $('#regular_button').button({text:false, icons:{primary:'ui-icon-help'}});
});

Here is what the resulting layout looks like...


Without much effort on out part, we've now got a help button accompanying our text input - ready to respond to click events and display contextual content.  However, we're more concerned with the look and feel of this context button.  Might it be that in this button in it's default form might be a little overkill?  Let's try making this help button a little less invasive. 

First, we'll build on our current HTML structure so we can compare the two button formats...

<body>
    <div>
        <input type="text"/>
        <button id="regular_button" title="Help">Help</button>
    </div>
    <div>
        <input type="text"/>
        <button id="icon_button" title="Help">Help</button>
    </div>        
</body>

Next, we're going to create a new button widget — one that builds on the default button implementation...

$.widget('ui.iconbutton', $.extend({}, $.ui.button.prototype, {
    _init: function() {
        $.ui.button.prototype._init.call(this);
        this.element.removeClass('ui-corner-all')
                    .addClass('ui-iconbutton')
                    .unbind('.button');
    }		
}));

$(document).ready(function(){
    $('#regular_button').button({text:false, icons:{primary:'ui-icon-help'}});
    $('#icon_button').iconbutton({text:false, icons:{primary:'ui-icon-help'}});
}); 
 

Finally, our new button implementation needs to be themed...

.ui-iconbutton {
    background: transparent;
    border: none;
}

The demo page now has two text inputs and two corresponding help buttons — the latter using our new button implementation that only shows the icon...


As you can see, iconbutton removes the border and background styles from the button — aside from that, we've got a regular button image.  With this widget customization, we're only modifying the appearance.

Did we have to create a custom widget just to remove the border and background styles from a button?  Could we not have just applied the appropriate help icon class to a span element and achieve the same result with less work?  Absolutely, we could have.  But in the end, creating a custom widget implementation has several benefits that aren't discernible at first.

The key advantage to this approach is that the iconbutton and button widgets are interchangeable.  Since the iconbutton is simply extending the button widget, it accepts the same parameters.  This is why I'm illustrating both buttons on the same page — the HTML and Javascript are identical except for the widget name.  What this means is that if you don't want the icon button any more, it can simply be replaced by a regular button.  Conversely, the icon button can replace regular buttons.