Home  >  

The YAHOO! User Interface Library - YUI

Author photo
AddThis Social Bookmark Button

Little more than a two years ago YAHOO! decided to make its library of cross-browser JavaScript components available to the public with a BSD license as the YUI, the YAHOO! User Interface library. It is now reaching the end of its second major version with dozens of minor versions, each new one bringing a few more components with it.

Since YAHOO! is the major user of YUI, actually, since the millions of users accessing YAHOO! are the major end-users, the YUI is a very effective tool (admittedly, not all YAHOO! uses the YUI yet). YUI was developed to satisfy an existing need in a tough and varied environment. Clients may be anywhere, with different bandwidths, can have different browsers with different settings and several applications might need to coexist in the same page.

The most unusual feature of YUI as a JavaScript library is, strange as it may sound, that it can work even if the end user does not have JavaScript enabled. YUI can be used to enhance existing markup, that is, a page can be produced by the server as a plain HTML page, functional but featureless. If JavaScript is enabled, the YUI can enhance it with all the modern features it provides. For example, the Rich Text Editor component expects an HTML textarea as its container. If JavaScript is not enabled, the user will still be able to edit plain text in the textarea. Menus and TreeViews can take an unordered list of links so that if JavaScript is not enabled, the page will be functional. This feature, though important to those who need to deliver services to the general public, has a cost, pages have to be designer to look good with both JavaScript enabled and without; since the initial markup has to be created dynamically pages cannot be cached on the client side and the server side has to be able to reply to both asynchronous and regular requests.

The YUI library also provides several CSS stylesheets. Some of them are meant to normalize the presentation across all browsers. For example, the default font sizes in different browsers are not exactly alike and these styles makes all sizes compatible. Another stylesheet provides several static layouts based on absolute positioning and floats (the library also has a dynamic layout component). Furthermore, several components have their own stylesheets controlling their visual presentation. YUI allows for a skinning mechanism and though YUI initially has provided only a single skin (the 'sam' skin named after its designer), some users have made their own and at least one has made his public.

The YUI library has been carefully designed to coexist safely with other third party code running on the same client such as mashups, ad providers, search boxes and such. The whole library uses a single name in the global namespace, YAHOO, thus avoiding collisions with variables declared elsewhere. HTML elements are the other point of contact in between libraries coexisting on a page. Here, the YUI library uses the yui- prefix for any identifier attached to an element, be it for the id attribute, classNames or extra custom attributes. Other libraries can be used at the same time as long as they don't use the YAHOO variable or the yui- prefix. Under this single variable name, several properties contain the several objects that make the library. All visible UI elements fall under YAHOO.widget: YAHOO.widget.Editor, YAHOO.widget.TreeView and so on. Under YAHOO.lang we find those functions that provide functionality that JavaScript should have but is missing, deficient or unreliable, such as variable type detection. Finally, YAHOO.util gathers all the rest such as DOM manipulation, event handling, asynchronous communication and others.

This subdivision of the YAHOO namespace should not be confused with 'components'. In YUI 'components' are basically delivery units. A single component might contain objects from more than one branch of the named above. The Menu component, for example, contains several objects under YAHOO.widget for their visible elements but it also has some under YAHOO.util, which are not visible but remain in the background keeping track of open menu panels.

The performance enhancements in the library have been continuous. The YUI team receives feedback from other departments within YAHOO!, some of them dedicated to performance, which then get reflected on the library. An important tool has been the YUI Compressor which is able to reduce the size of the JavaScript and CSS stylesheets to improve delivery time. For the smaller components, where the latency time is greater than the transmission time, several such components were packed into a single file which, once compressed, can be delivered in the shortest possible time. These are called aggregate files. The YUI team has even re-written several of the components to maximize the compression rates, for example, avoiding references to long global names, which cannot be minimized, using local variables instead. And if you are concerned that your servers might not be capable of efficiently delivering those components worldwide, YAHOO! has placed the library in its own distributed servers for public access so your servers only need to provide your application and YAHOO! delivers the YUI library itself.

YUI achieves an unusual balance. Though programmers might find other libraries more elegant or cleaner, YUI satisfies most of those involved in delivering enhanced applications to end users. It is tested in all major browsers, it has a small size/performance ratio, it has been carefully designed to coexist with other code on the client machine, it is flexible in the communication options with the servers so that even existing applications might be enhanced by YUI without requiring major reworking on the server side and it can even allow you to deliver workable pages to browsers with JavaScript disabled.

The YUI library is very well documented. Besides the API reference, produced automatically from the original source code, the user guides and the examples cover most of the features. The YUI blog and YUI Theater provides some more in-depth articles, pointers to related material elsewhere, news and videos.

The next major version will bring a reordering of the library since its own unexpected growth has introduced a few inconsistencies. This will certainly satisfy the programmers who want a cleaner library. It wasn't until some common patterns were detected in several of the components that some base objects were developed and though now all new components inherit from those, the old ones still have their own ways. More exciting will be the possibility of third party participation in code development. So far, the YUI team is the only one working on the library, with external developers able to participate through SourceForge in reporting bugs and suggesting future features and the mailing list. With the reordering of the library and the establishment of clearer guidelines, third parties will be able to effectively develop new components or add to existing ones.

Loading components

There are two ways to load the YUI components, you can do it directly via <script> and <link> tags, as shown in most examples or in Eric Miraglia's article or you could use the YUI Loader. The Loader is often overlooked in the documentation. The 'Getting Started' section of each component usually lists the library dependencies providing a code block which you can copy and paste right into your code. Most people miss to read the brief sentence that gives the name you need to provide the YUI Loader to load the component and all its dependencies. Admittedly, using the YUI Loader is slower than including the library files directly since none of the files will even start to load until after the Loader itself has loaded and decided what to do. If performance is an issue, then it is better to load components directly. To help you handle dependencies, specially when there is more than one component involved, the configurator utility lets you build your own includes, otherwise, the YUI Loader is the easiest choice. The configurator actually uses the YUI Loader to build the dependency lists.

Assuming that in your HTML page you have included the script for the YUI Loader:

<script src="http://yui.yahooapis.com/2.5.1/build/yuiloader/yuiloader-beta-min.js"
type="text/javascript"></script>

Then you just need to put this code in the accompanying JavaScript

(function(){
     var loader = new YAHOO.util.YUILoader();
     
     loader.require('editor','datatable');
 
     loader.insert({
          // filter: 'raw',  // or filter:'debug',
          // base: '/yui-2.5.1/build/',
          loadOptional: true,
          onSuccess: function(){ 
               YAHOO.util.Event.onDOMReady(function () {
    
                    // your code here
    
                });
           },
          onFailure:function(msg) {
               YAHOO.log(msg,'error','myPage');
           }
      });
})();

The above sample carry lots of information, lets analyze it. In the <script> tag you can see the address for the YAHOO! servers which can be used to load the YUI library. The servers have copies of all the public releases of the library since unavoidable differences in between versions might make one version slightly incompatible with previous ones. By having a folder for each version, you can stick with the version you know your application works with instead of rushing to change your application when the YUI version changes. The filename for the YUI Loader component also tells us that it is still beta and we are loading the compressed version ('minified', thus the -min suffix).

The JavaScript code that follows is enclosed in an anonymous function. Its purpose is to turn all the variables declared inside, such as loader, local to that function and, thus, not visible in the global scope. Notice the very last set of empty parenthesis at the bottom of the code box indicating that the function is immediately executed. Within that anonymous function we declare a variable loader which we initialize with an instance of the YUI Loader. This is the first YUI component we are using. As we mentioned, all YUI components are defined under the YAHOO namespace. If, just as we did, we define all our own variables as local to an anonymous function, we are further protected from the risk of namespace collisions.

We then declare which components we want to load. There is no need to get concerned with dependencies and such, the loader will take care of that. We are asking here for the DataTable and the Rich Text Editor components. This will also load any stylesheets associated with these components and if within the dependency files it finds any group that belong to an aggregate file, it will load that one, unless you explicitly tell it not to by setting the allowRollup option to false.

Finally we tell the loader to insert the requested components into our page. The insert method takes an object literal as its argument specifying several options. The main one is the onSuccess property which will be called when all scripts and stylesheets requested have been loaded and are ready to use. However, this does not mean that the page itself is ready to use. Though in many cases the body of the page will be loaded by the time the loader finishes its work, there might be cases when it is not, for example, when the page contains information from many database queries which might delay its completion. So, we make a further check to see if the DOM is ready for us to use via method onDOMReady which we call passing it a function which it should call when everything is ready. That is the place for our code, everything we could need should be ready. At this point we are three levels deep into functions contained within functions so any variables we declare inside are local to that function and not visible elsewhere (variables used but not explicitly declared will go into the global namespace, a source of much frustration when they collide with others with the same name).

The loader has several options such as filter which lets you specify which version of the files to load. By default, the compressed versions get loaded but you can specify 'raw' to load the regular version which still has all the formatting, comments and original variable names so it can be stepped through with a debugger and make sense of it, or the 'debug' version which has extra code to log messages into the YUI Logger, another component of the library which is also available to developers to log their own messages in a consistent way in all supported browsers.

The base option allows you to change the default base path for all library components. By default the components get loaded from the YUI servers, if you don't want that, you can say so. The loadOptional option lets you specify whether you want some extra non-vital dependencies that provide a layer of icing such as animated movements or drag and drop. Finally, the onFailure function gets called if anything went wrong and it provides a message indicating the cause. We are using the YUI Logger to show it. The YUI Logger might be loaded or not, the call to YAHOO.log won't fail if it hasn't. In this example, we have not loaded it, but it is still good to have those log messages in your code just in case something does go wrong. Though the Logger can be loaded by including the name 'logger' in the call to loader.require, to log any messages produced by the Loader, it needs to be included separately, just as the Loader itself.

Loading your own Components

We can use the YUI Loader to load our own code and libraries. We do this by using the addModule method:

loader.addModule({
     name: 'myModuleName',
     type: 'js',
     fullpath: 'js/myModule.js',
     requires: ['myLibrary', 'datatable', 'connect']
});

We have to give each module a name which can later be used in require lists, tell the loader whether it is a JavaScript or CSS file, the path to locate it and its dependencies which can be any mix of YUI components and our own which should be declared elsewhere with this same addModule method.

To let the loader know when a module has been loaded, we need to add a line of code at the end of each.

YAHOO.register('myModuleName',entryPoint,{version:'2.5.1',build:'0'});

The first argument should be the same name given to the addModule method. If a module fails to register, the Loader.insert method will remain waiting and will never call the onSuccess callback function.

While page code can, for the most part, be contained within the local scope of a function and thus avoid cluttering the global namespace, libraries have to be public and expose some of its members. We may device and manage an schema analogous to the YAHOO namespace or we may fit within by using the YAHOO.namespace function:

YAHOO.namespace('myOrganization'); 

This will create a YAHOO.myOrganization object which can be later populated with your own library objects. This call can be safely repeated in each of your library modules since it does not clear any previous contents, if there is any.

Amongst the several objects we will likely include in our libraries are our own customized versions of YUI objects. From SimpleDialog we might derive confirmation or information boxes styled to our site, from Panel we can make wait or 'in progress' boxes or we might tailor the Rich Text Editor by adding or removing tools from its toolbar or adding a completely separate toolbar.

Functions YAHOO.lang.extend and YAHOO.lang.augment are very helpful in doing that. They are located in the lang branch since, in a language which in principle allows inheritance, it is quite funny that there should be no built in method to do it. Both methods could and ideally should be added as prototypes to the Object object but to avoid clashes with other code, the YUI library never modifies the base libraries and it tries, as much as possible, to be tolerant should it find them modified by others.


The YUI library is a solid and ever growing product. It has a very demanding in-house user, which constitutes a huge user base on its own though it is far from the only one. The YUI team is very responsive, all its members are regular contributors to the mailing list, many of them providing helpful articles and examples in their own personal web sites. The product is well documented and, should all else fail, the (uncompressed) code itself is clear and well commented. The community of developers is also quite big with several of its members quite knowledgeable in many of the components so there are few questions that remain unanswered for long.

In later articles, we will try some of its components

Read more from Daniel Barreiro. Daniel Barreiro's Atom feed

Comments

2 Comments

YUI was an eye opener for web developers.
It was an example of the level of quality that a (javascript) framework can achieve when an entity the size of Yahoo puts its resources behind it.

In my perception as a web developer, YUI raised the bar and marked the beginning of ajax as an enterprise level framework to deliver web interfaces. Soon after YUI, Ext JS appeared on the map as -the- apex of ajax.

But, YUI still stands as the pattern to follow when good'ol unlimited backwards compatibility is a requirement.

Ryan I said:

I started using YUI very early on. One of the reasons I choose to use it vs using prototype was that it had so much good documentation.

The most exciting piece of YUI in the 2.x versions have been the focus on web performance.

Leave a comment


Tag Cloud

Poll: Mobile Features

What feature do you use most on your mobile phone?

Vote | View Poll Results | Read Related Blog Entry

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.