Using Multiple jQuery UI Themes on a Single Page

Posted by Scott on 02/18/2009

Topics:

If you're using the jQuery UI CSS Framework to design an entire interface, you may find that one theme is not enough. This quick tutorial will highlight a new feature in the jQuery UI Download Builder which allows you to easily use multiple themes on a single page.

The Problem

We often get questions about how we'd recommend implementing multiple themes on a single page. The situation arises when you're using the jQuery UI CSS Framework to style many elements in one interface and they begin to look too similar. In the past, you would have had to do some handy work with regular expressions to add CSS scope to all selectors in ui.theme.css, and rename your theme folder so it could sit in the same directory as another theme. Unfortunately, while this process was certainly doable for an experienced developer, it was a lot more complex than we think it should be for such a common task.

The Solution

The New Advanced Theme Settings

We decided to implement a solution in the download builder which automates the process of applying scope to a theme and renaming the theme folder. The new feature is available in the Themes section of the download builder, under advanced settings.

First Things First

In order to take advantage of theme scoping, you'll first need to select a theme. You can choose from several themes from the gallery from within the download builder, or you can go to ThemeRoller and design a theme first. When you download your theme in ThemeRoller, you'll be directed back to the download builder again to customize your download.

Entering a CSS Scope

The theme scope field is where you'll enter a CSS selector representing a portion of your page (or your site) that your theme should apply. For example, if you have an accordion widget in the side navigation column of your site and you want it to have a different theme than other areas of your site, you can type the CSS selector that corresponds with that side navigation column (such as .interiorNavigation) and download your theme. The builder will add a space after your scope selector as well, so don't worry about needing to add one.

Typing into Theme Settings

...and a Folder Name

As you type your CSS scope, the builder will suggest a corresponding theme folder name. This name can be edited, and it won't auto-suggest another one unless the folder field is empty or un-edited when you type in the scope field.

After Downloading

Once you download and unpack the zip file, you'll see that it contains a theme folder named either "theme" or whatever custom name you entered in the Theme Folder field. Inside that folder you'll find all of the files that make up the jQuery UI CSS Framework. Assuming you entered a scope in the Theme Scope field, all of the CSS included in this folder will be scoped to your selector.

Unzipped jQuery UI Download Folder

A snapshot of the unzipped folder. Note that scoped theme downloads will not include an example page, due to the complexity of recreating your scoped markup.

To included this theme on your page, just direct a CSS link to ui.all.css in the "theme_internalNavigation" folder.


<link type="text/css" href="theme_interiorNavigation/ui.all.css" rel="Stylesheet" />	

That's it!

You've now included a theme that is scoped to a specific part of your site. You can do this as many times as you'd like - though you should be cautious of filesize as it will add up very quickly!

Quick Demo

The following example demonstrates the result of the steps outlined in this article. We've linked to both a regular unscoped theme and a second theme scoped to the .interiorNavigation selector (as demonstrated above). The demo page features two tab widgets, the second of which is contained in a div with a class of "interiorNavigation" allowing it to receive the scoped theme styles.

Demo page

Download Zip

By the way...

If you're interested in designing with the new jQuery UI CSS Framework, we encourage you to check out our contest to win tickets to SXSW.

And be sure to check out these other articles concerning jQuery UI:

Book cover: Designing with Progressive Enhancement

Enjoy our blog? You'll love our book.

For info and ordering: Visit the book site

Comments

This is definitely interesting, and I can see its usefulness to some.  However, how does this relate to the ThemeRoller bookmarklet?

To me, the bookmarklet is a very important piece of the jQuery UI CSS Framework puzzle.  If this breaks the ability to use the bookmarklet as a WYSIWYG theme editor, then I’m not convinced this multiple-theme strategy is the best solution. That is, unless you plan on somehow implementing multiple theme management into the ThemeRoller.

My suggestion remains adding custom levers to the ThemeRoller so that we maintain one, singular theme.  This one theme could bring in the styling from other themes’ levers.  For example, I could bring in the Content styling from the UI lightness theme and bring in the Header/Toolbar styling from the UI darkness theme.  In addition, if I want to define a lever for Page Background, I can do that.  If I want to add a lever for Alternating Table Rows, I can do that too.  This gives more variety per theme and keeps it one theme instead of keeping up with many.

Some method of defining what levers a theme styles would need to be discussed, and, of course, there would need to be a core set of levers that a theme would be required to style.

Comment by Tony on 02/19  at  09:06 PM

@Tony: The bookmarklet can be thought of as a design tool, just like ThemeRoller itself. The only difference is that the bookmarklet allows you to “roll” a theme for widgets that are not part of jQuery UI. This is a benefit to plugin developers who want to offer widgets that are flexible enough to be integrated easily into existing websites.

As for the combining of themes you’re talking about - this is what ThemeRoller is all about! The gallery themes are fine if they fit your needs, but most users will want to use the roll your own interface to design a custom theme. What you’re trying to do is already very doable in ThemeRoller. You can design each framework lever exactly how you want it to look. In fact, we designed every theme in the gallery by using ThemeRoller’s existing levers. They all resolve to the same kind of query string that a custom theme does, and you can always open a gallery theme and tweak it to your needs too.

Keep in mind that this article is dealing with an edge case, not the primary use of UI themes. Most of the time, one theme will do everything you need. It’s not until you start doing full interface layout with lots of framework components on a single page that you’d need multiple themes and scoping.

As for your page background example, you can certainly do that by applying a framework class like ui-widget-content to your container element. And if you need multiple themes to achieve that, then you could scope them. ThemeRoller only styles the commonly used framework classes - never dealing with specific widgets. This allows you to separate your theme styles from structural styles, and we do this in UI as well: see slider widget CSS: http://jquery-ui.googlecode.com/svn/trunk/themes/base/ui.slider.css (only structural styles - nothing theme-related except resets).

In general, we designed the framework with UI component design in mind - ideally components that sit within a larger layout system, but we’re eager to see it get pushed further. We may add more levers in the future but they’ll probably follow our path of commonly used UI elements. For example, we don’t currently have a ui-widget-footer class, among other things. This would be in keeping with a framework that can be useful to any widget developer.

I hope this helps. let us know!

Comment by Scott (Filament) on 02/19  at  11:56 PM

This approach does not seem to work with dialogs since they are created on top of the body tag and thus are not in the css predefined namespace. Is there any workaround for that?

Comment by Sasha on 05/12  at  09:08 PM

@Sasha: This is true and also a problem with the datepicker plugin. In the near future, we plan to include a “helperClass” option to all overlay-style plugins in jQuery UI, which will solve this problem. Tentatively, the idea is that you can pass a class name to this option and the plugin will create a static div with that class on it and wrap it around the dialog’s outer div. This helper div could then be used to achieve theme scoping.

For now, you should be able to do it with a script workaround. For example, when you create your dialog, you can wrap it with a classed div, like this:

$(’.selector’).dialog().parents(’.ui-dialog:eq(0)’).wrap(’<div class="myScope"></div>’);

Then you can scope your theme to “.myScope”.

Note that we have to call the parents() method because the dialog plugin is created and referenced through it’s content panel. In other words, the element you call dialog() on becomes the content panel of the dialog.

Let us know if that helps!

Comment by Scott (Filament) on 05/12  at  09:27 PM

@Scott:
wow, this worked out just great. Thanks for the quick and right answer, I really appreciate it.

Comment by Sasha on 05/12  at  10:57 PM

This solution works well if you only ever use themes generated entirely by themeroller. Due to the nature of CSS using a descendant selector for scoping forces you to clear all of the styles set by the unscoped theme. This quickly becomes a pain if you are manually creating your theme. The solution seems to be to scope all of your themes and put your widget in the appropriate scope. This is a lot of css to load to have mutliple tab styles on each page, not to mention the extra cruft in your html. Including the namespace in the acutal class name and then telling jquery UI to use that namespace would avoid the cascading problem. ( ui-tabs-nav -> myui-tabs-nav) This however would require some changes to the the jquery UI. The tabs widget used to have to options to specify custom classes, however this was taken out to make the library more uniform and pretty. The result is that now all the users of the library have to put hacks in our code and have bloated css. Has this sort of proper namespacing been considered by themeroller/jquery ui team?

Comment by Andrew on 05/27  at  10:21 PM

Can we get rounded corners working on dialog in IE7/IE8 using wrap div as you suggested above?

Comment by sduffer on 05/28  at  09:41 AM

I’m not getting this to work, though it makes sense, and I have multiple tabs on my homepage.  (What is linked is a beta page.)

Comment by Jim R on 06/17  at  02:59 PM

@Scott Can you show an example using the datepicker? (similar to dialogs)

I tried this and it didn’t work:
$(’#startDate’).datepicker().parents(’.ui-datepicker:eq(0)’).wrap(’<div class="redmondTheme"></div>’);

Comment by Hillary on 07/07  at  12:27 AM

This approach does not seem to work with dialogs since they are created on top of the body tag and thus are not in the css predefined namespace. Is there any workaround for that

Comment by توبيكات on 08/16  at  02:06 AM

@Hillary (and anyone else who wants to single out the datepicker) - I was able to wrap the datepicker widget with a wrapper div with a class of ‘cal’ by using the following code:

$(".datepicker").datepicker().closest(’body’).find(’#ui-datepicker-div’).wrap(’<div class="cal"></div>’);

‘.datepicker’ is the class I have applied to my text inputs that need the datepicker widget, and ‘.cal’ is the class on my div to wrap the datepicker. (change these two classes as needed for your application)

If there is a more elegant/efficient way to target ‘#ui-datepicker-div’ instead of using `.closest(’body’).find(’#ui-datepicker-div’)` please share!

Comment by Andy Ford on 08/28  at  06:55 PM

Hi at all,

When i download theme with custom scope version 1.7.2, something goes wrong.

In the zip i can see a demo folder which use the Basic theme by default, that is not a problem because i make my own changes; the problem is that if i try to do what you say nothing goes! I need to use (in the dialog widget for example) the option dialogClass: ‘MyScope’ and i can see my dialog. And here i have my true problem, the dialog appear but with some style error. In my case the cross (close button) go in newline under title, the fontname isn’t what i expect, and other things. Tested with IE8 , FF3 , CH2.

Can anyone help me?

Comment by Michael Sogos on 09/06  at  03:43 PM

I already tried the demo in zip, and it goes. My problem is that i’m using the 1.7 version of UI Framework and not 1.6 (the version in the zip is 1.6), probabily something was changed between this version. Can you try to make a new zip example with the 1.7 version, please?

Comment by Michael Sogos on 11/11  at  10:28 PM

Seems it doesn’t work with datepicker or I do something wrong.
jquery 1.7.2
jquery-ui.1.7.2

Comment by plastic on 12/03  at  07:47 PM

The autocomplete widget is another problematic one, when it comes to using a scope. Here’s yet another method to sort it out:

$(window).load(function() {
$(’.ui-autocomplete’).wrap(’<div class="css_scope_selector" >’);
});

@Scott, Any progress on that ‘helperClass’ you spoke of?

Comment by BK on 07/01  at  10:47 PM

Another way to add the wrapper around the datepicker is to do this via the beforeShow method in the config options:

beforeShow: function(input, inst) {
var newclass = ‘calendar-base’;
if (!inst.dpDiv.parent().hasClass(’calendar-base’)){
inst.dpDiv.wrap(’<div class="’+newclass+‘“></div>’)
}
}

Comment by Brook on 08/11  at  01:02 AM

@Brook: Thanks. Nice idea for using the beforeShow option!

If anyone is having trouble using a scoped theme with datepicker, check out Brook’s comment above.

Comment by Scott (Filament) on 08/12  at  05:19 PM

I’m trying to use a theme within a theme eg.

<div class = “theme1">
<!---tab info --->
<div class = “theme2">
<!---tab info --->
</div>
</div>

This seems to work....sometimes. Sometimes the tab in theme2 takes the values for theme1, sometimes it doesnt, whenever i interchange themes. does anybody know what would cause that?

Comment by icuucme on 08/20  at  05:11 PM

wow! nevermind, i figured it out. it depends on the order that you load the CSS file. i guess thas how it is in basic css.

Comment by icuucme on 08/20  at  05:33 PM

This seems to work....sometimes. Sometimes the tab in theme2 takes the values for theme1, sometimes it doesnt, whenever i interchange themes. does anybody know what would cause that?

Comment by hjfgh on 09/02  at  09:46 AM

what is a css scope? This is not a good tutorial… you should explain things in more detail… or do i have to spend 5 days to try to figure this out??

Comment by mitja.gti on 10/05  at  03:54 PM

Alright, so here’s my issue.  Modal dialog boxes, with multiple themes don’t seem to work.

When you specify the option of modal, on a dialog box wrapped with:

parents(’.ui-datepicker:eq(0)’).wrap(’<div class="redmondTheme"></div>’); .

in a multi-themed page, the modal overylay doesn’t kick in on the webpage.

Comment by Rookerith on 02/15  at  09:43 PM

I have a page with multiple dialog styles, one of my style sheets is scoped and one isn’t. Dialogs are tricky with scoped style sheets because when the dialog is created it’s moved from it’s place in the page and appended to the <body> tag. So if your element is in scope before the dialog is created, it won’t be after you create the dialog. You can see this easily in FireBug. You can follow the methods above by re-wrapping the dialog after it’s created but I found it easier to do this for my purposes. (note, I don’t have any other jQuery UI elements on my page.)

$("body").addClass(scoped-class-name);
$("#dialog").dialog();

Then bind to the dialog close method to remove the scoped class name

$("#dialog).dialog("close", function(){$("body").removeClass(scoped-class-name);});

This solved my problem with multiple dialog styles, but if you have other jquery ui elements on your page and you change the class on the body you’ll likely break the style.

Comment by bzink on 04/09  at  11:24 PM

I have the following code, and I have a custom theme created with the theme roller (scpeName). When I launch the following code, my overlays don’t show up. I read all the comments here on this page and I tried them all and no luck :( Can someone help me with this one please.

$(document).ready(function(){
$("#confirmDelete").dialog({
modal: true,
bgiframe: true,
autoOpen: false });
});

$(’#ui-dialog-div’).wrap(’<div class="cclicks"></div>’);

did not do the job for me. Please advice of any working solutions.

Thanks,

Nikkie

Comment by Nikke on 04/24  at  10:15 AM

Commenting is closed for this post.

Book cover: Designing with Progressive Enhancement

Enjoy our blog? You'll love our book.

For info and ordering: Visit the book site