type: widget
release: 0.0
status: in planning
documentation: url || N/A
demo: http://jquery-ui.googlecode.com/svn/branches/labs/selectmenu/index.html
Bugfixed and jQuery 1.4.x / UI 1.8.x compatible version of this plugin: Please download repo at http://github.com/fnagel/jquery-ui/tree/selectmenu and open: demo/selectmenu/index.html
Feel free to post feature requests and bugs in the comments or even better in the GitHub issue tracker. This edit was made after consulting Todd Parker.
1 - Description:
A jQuery UI widget that duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
2 - Visual Design:

3 - Functional Specifications/Requirements:
The default way to use this plugin is by calling the .selectmenu method on a select element:
$('select').selectmenu();
Feature details:
- selectmenu will act as a proxy back to the original select element, controlling its state for form submission or serialization
- If the hideElement option is true, the original select element will be set to display: none after selectmenu is created. The original select menu will not be removed from the page because it will retain the widget state for form submission.
- Any form label originally associated with the select menu will be re-associated with the new form control. Clicking it will focus the new selectmenu.
- The menu will support both in-place "popup" or drop-down styles
- The menu will be fully keyboard accessible using matching conventions to native select elements
- Menu is keyboard accessible while closed as well - arrow keys make different selections
- The menu will have ARIA support for screenreaders so the original select element can safely be hidden from all users
- Different arrow icons depending on menu type
- The format option accepts a function with a single argument that can be manipulated and returned with any level of manipulation you'd like.
Still needs to be built:
- collision detection and stackfix / iframe
- disabled method doesn't truly disable widget
Options:
- transferClasses: true, transfer classes from select to both button and menu container (option classes are always transferred)
- style: 'popup', also avail: 'dropdown'
- width: null, defaults to select width, accepts a number
- maxHeight: null, sets the maximum height for the menu body
- menuWidth: null, sets menu body separately. defaults to width option value, accepts a number
- handleWidth: 26, number width that the icon arrow block will hang off the edge in a 'popup' style menu
- icons: null, array of objects with "find" and "icon" properties. "find" is a jQuery selector, "icon" is a jQuery UI framework icon class ("ui-icon-script").
- format: null, array of objects with find and rep properties. Each will run in order and perform find/replace formatting. For example: format: [{find:/^([a-zA-Z0-9 ]+)\-/g, rep: '<span class="header">$1</span>'} will find all text before a " - " and wrap it with a span.header.
Callbacks/Events: (each returns the event as first arg, second arg is the ui hash, which currently contains properties: "value")
- Open
- Close
- Change
- Select
- Value
4 - Markup & Style:
4.1 Initial markup examples
<select name="speedA" id="speedA">
<option value="Slower" class="whoo">Slower</option>
<option value="Slow">Slow</option>
<option value="Med" selected="selected">Med</option>
<option value="Fast">Fast</option>
<option value="Faster">Faster</option>
</select>
4.2 Recommended transformed HTML markup
<a aria-owns="speedA_menu_318" aria-haspopup="true" href="#" id="speedA_button_318" class="ui-selectmenu ui-selectmenu-popup ui-widget ui-state-default ui-corner-all" tabindex="0" style="width: 173px;">
<span class="ui-selectmenu-status">Slower</span>
<span class="ui-selectmenu-icon ui-icon ui-icon-triangle-2-n-s"></span>
</a>
<!-- at end of body-->
<ul id="speedA_menu_318" role="menu" aria-labelledby="speedA_button_318" class="ui-selectmenu-menu ui-widget ui-widget-content ui-corner-all ui-selectmenu-menu-popup ui-selectmenu-open" style="width: 147px; left: 184.017px; top: 136.95px;">
<li class="whoo ui-corner-top ui-selectmenu-item-selected ui-state-active"><a aria-selected="true" role="option" tabindex="-1" href="#">Slower</a></li>
<li><a aria-selected="false" role="option" tabindex="-1" href="#">Slow</a></li>
<li><a aria-selected="false" role="option" tabindex="-1" href="#">Med</a></li>
<li><a aria-selected="false" role="option" tabindex="-1" href="#">Fast</a></li>
<li class="ui-corner-bottom"><a aria-selected="false" role="option" tabindex="-1" href="#">Faster</a></li>
</ul>
4.3 Accessibility recommendation
Attributes on button:
- aria-haspopup="true"
- aria-owns="[widget menu's id value]"
- generated ID for ARIA element referencing
- tabindex of 0 or value from select element
- aria-disabled (accordingly)
ARIA attributes on menu portion:
- role="menu"
- aria-labelledby="[widget button's id value]"
- generated ID for ARIA element referencing
- Each anchor within menu requires :
- aria-selected="true/false"
- tabindex="-1"
- role="option"
4.4 CSS & Theme
/* Selectmenu
----------------------------------*/
.ui-selectmenu { display: block; position:relative; height:2em; text-decoration: none; overflow:hidden;}
.ui-selectmenu-icon { position:absolute; right:6px; margin-top:-8px; top: 50%; }
.ui-selectmenu-menu { padding:0; margin:0; list-style:none; position:absolute; top: 0; visibility: hidden; overflow: auto; }
.ui-selectmenu-open { visibility: visible; }
.ui-selectmenu-menu-popup { margin-top: -1px; }
.ui-selectmenu-menu-dropdown { }
.ui-selectmenu-menu li { padding:0; margin:0; display: block; border-top: 1px dotted transparent; border-bottom: 1px dotted transparent; border-right-width: 0 !important; border-left-width: 0 !important; font-weight: normal !important; }
.ui-selectmenu-menu li a,.ui-selectmenu-status {line-height: 1.4em; display:block; padding:.3em 1em; outline:none; text-decoration:none; }
.ui-selectmenu-menu li.ui-selectmenu-hasIcon a,
.ui-selectmenu-hasIcon .ui-selectmenu-status { padding-left: 20px; position: relative; margin-left: 5px; }
.ui-selectmenu-menu li .ui-icon, .ui-selectmenu-status .ui-icon { position: absolute; top: 1em; margin-top: -8px; left: 0; }
.ui-selectmenu-status { line-height: 1.4em; }
.ui-selectmenu-open li.ui-selectmenu-item-focus a { }
.ui-selectmenu-open li.ui-selectmenu-item-selected { }
.ui-selectmenu-menu li span,.ui-selectmenu-status span { display:block; margin-bottom: .2em; }
.ui-selectmenu-menu li .ui-selectmenu-item-header { font-weight: bold; }
.ui-selectmenu-menu li .ui-selectmenu-item-content { }
.ui-selectmenu-menu li .ui-selectmenu-item-footer { opacity: .8; }
/*for optgroups*/
.ui-selectmenu-menu .ui-selectmenu-group { font-size: 1em; }
.ui-selectmenu-menu .ui-selectmenu-group .ui-selectmenu-group-label { line-height: 1.4em; display:block; padding:.6em .5em 0; font-weight: bold; }
.ui-selectmenu-menu .ui-selectmenu-group ul { margin: 0; padding: 0; }
5 - Latest version of plugin:
6 - Open issues being discussed
- Should the enter key, when pressed on a focused-but-closed button, submit the parent form?
- Event callbacks arguments - what should they be?
- Should we have an option for shadow support on the menu?
- Should we have an option for scrollbarless slick scrolling (arrows at top and bottom and list scrolls dynamically with mouse position)?
- ARIA attributes currently in use have been questioned. Discussion here: http://groups.google.com/group/jquery-ui-dev/browse_thread/thread/f4f81a2d91761478
- Positioning of menu is a little off in the optgroups example.
7 - Related jQuery plugins
Comments (Show all 53)
sompylasar said
at 6:52 am on Sep 6, 2009
Font families are the same but font-weight is different which leads to a noticeable jump in the width of text.
ajpiano said
at 5:08 pm on Sep 10, 2009
The format callback certainly doesn't match the one in the spec...not that it ought to. Format should be (and is) a callback, not a hash of find and replaces. The _formatText method ought to pass the text and the actual OPTION element to the format callback, instead of just the text. This allows for much more versatility in formatting the list items.
ajpiano said
at 11:54 am on Sep 13, 2009
There is also a bug in type-ahead that eats up ctrl+keypresses. Surprised no one ran into this, as it breaks ctrl-r!
ajpiano said
at 3:44 pm on Sep 16, 2009
There is no reason that maxHeight shouldn't be compatible with dropdown style, in my estimation. I was using maxHeight on a selectmenu, but it was getting jittery over the window edge. When i took out the if (style=="popup") in the mouseup that uses the timeout to delay for the safemouseup, the maxHeight works fine in both styles.
jacobstr said
at 7:09 pm on Sep 27, 2009
What's the hold up with this? This seems like a much more fundamental, and core widget than something like autocomplete (which I can build myself) and shadow (which I won't even use because the slow-down isn't worth the minor visual flair). Yet, it's rated as very low priority?!
I'm sure everyone here that has used jquery ui in a project has run into the situation where 90% of your widgets are looking nice and consistent. You can replace all your buttons and text inputs, with equivalent markup and jquery ui styles (ui-state-default). We don't need to do anything special for text inputs to achieve a similar look (background + border are sufficient here). The things you can't really style in a satisfying way without javascript are select menus and radio/checkbox buttons. The normal HTML widgets (as well as file uploads and fieldsets) are too wonky in their styling.
Not only is this way too low priority (IMHO), unlike some of the other proposals on here, this one is nearly complete. It's also a plugin that I would hate to write myself, without nice community to help support it . Transparently replacing HTML select widgets better be done properly, and when some random use case comes up where it's broken it's great to have lots of eyes on it to fix it. If your fancy select widget is broken in ie 7 and you can't change a parameter in the back end of your web app because of it, your users have a right to be PO'd.
Klaus Pesendorfer said
at 4:34 am on Dec 16, 2009
The optgroup labels do not work with spaces.
I've solved this problem with the fix below:
- use the label only to display and reduce the label to an id without spaces for all other statements
... maybe this could be improbed to remove all special characters that are not allowed as css-class-name
===================================================================
--- ui.selectmenu.js 2009-12-15 16:35:05 UTC (rev 5596)
+++ ui.selectmenu.js 2009-12-15 17:17:52 UTC (rev 5597)
@@ -122,7 +122,8 @@
text: self._formatText(jQuery(this).text()),
selected: $(this).attr('selected'),
classes: $(this).attr('class'),
- parentOptGroup: $(this).parent('optgroup').attr('label')
+ parentOptGroup: $(this).parent('optgroup').attr('label').replace(/\s/g, ""),
+ parentOptGroupLabel: $(this).parent('optgroup').attr('label')
});
});
@@ -165,7 +166,7 @@
this.list.find('li.' + optGroupName + ':last ul').append(thisLi);
}
else{
- $('<li class="'+self.widgetBaseClass+'-group '+optGroupName+'"><span class="'+self.widgetBaseClass+'-group-label">'+selectOptionData[i].parentOptGroup+'</span><ul></ul></li>')
+ $('<li class="'+self.widgetBaseClass+'-group
+'+optGroupName+'"><span
+class="'+self.widgetBaseClass+'-group-label">'+selectOptionData[i].pare
+ntOptGroupLabel+'</span><ul></ul></li>')
.appendTo(this.list)
.find('ul')
.append(thisLi);
Klaus Pesendorfer said
at 4:45 am on Dec 16, 2009
Is there a possibility to select an entry in the selectmenu by the option-value (<option value="123">label</option>) of the original select element and not by the index?
$('#mycombo').selectmenu('value', elemlIndex);
It would be nice to have such a method!
Wichert Akkerman said
at 10:39 am on Dec 23, 2009
I feel that the format function should be passed the option element in addition to (or perhaps even in place of) the text. Let me explain a use case for this: I am creating a select menu to select the brand of a product. For each brand I also want to show the logo in the select menu. The non-javascript markup looks like this:
<select>
<option style="background: url(/contentstore/123d1231.jpeg) no-repeat left" value="1">Adidas</option>
<option style="background: url(/contentstore/2341a112.jpeg) no-repeat left" value="1">Nike</option>
</select>
Firefox the logo will show the logo correctly in the select menu. Other browsers ignore the style on the <option> element. When using selectmenu on this markup I want to extract the background image URL in my format function and use that to create a <img> element. This is only possible if the format method gets the <option> element as parameter as well.
Scott González said
at 10:59 am on Dec 23, 2009
1
Wichert Akkerman said
at 6:52 am on Feb 23, 2010
Here is the changeset I used to implement this locally:
@@ -390,8 +393,8 @@ $.widget("ui.selectmenu", {
if(this.list.is('.'+ this.widgetBaseClass +'-open')){ this.close(event,retainFocus); }
else { this.open(event); }
},
- _formatText: function(text){
- return this.options.format ? this.options.format(text) : text;
+ _formatText: function(text, el){
+ return this.options.format ? this.options.format(text, el) : text;
},
_selectedIndex: function(){
return this.element[0].selectedIndex;
@@ -119,7 +119,7 @@ $.widget("ui.selectmenu", {
.each(function(){
selectOptionData.push({
value: $(this).attr('value'),
- text: self._formatText(jQuery(this).text()),
+ text: self._formatText(jQuery(this).text(), this),
selected: $(this).attr('selected'),
classes: $(this).attr('class'),
parentOptGroup: $(this).parent('optgroup').attr('label')
Tauren Mills said
at 11:34 pm on Sep 1, 2010
Can you explain what this solves? I posted a comment below about better image support, would you patch solve the problem I describe? Basically, I want to display a Gravatar image next to a person's name. Does it work cross-browser, or just in FF?
Wichert Akkerman said
at 6:39 am on Dec 24, 2009
The current implementation does not match the spec form this page: the value property in ui hash passed to events does not specify the value of the selected option, but the index of the selected option.
I am not sure if there is a need for a new ui hash data type; perhaps it would be simpler to just include the original <option> element? That already has the value and any other data that you might want.
Nathan L Smith said
at 8:38 am on Jan 7, 2010
The plugin does not behave correctly in environments where Array.prototype is augmented. There's a patch here: http://dev.jqueryui.com/ticket/5034
Wichert Akkerman said
at 6:46 am on Feb 23, 2010
If you click on the menu to open it it is immediately closes again. This is different from a standard <select> which stays open until it looses focus. The only way to keep it open appears to be hold down your mousebutton and move the mouse down until you hover over an item, then move the mouse outside of the menu and release the button.
Wichert Akkerman said
at 6:48 am on Feb 23, 2010
The behaviour for a large list of options is suboptimal at the moment. The entire list can be (much) larger than the current page height, in which case the page is stretched to make room for the entire list, which adds a lot of empty space to the page. Selecting items at the end of the list is very awkward since there is no scroll option, and the menu often closes before you found the item you are looking for.
Wichert Akkerman said
at 6:50 am on Feb 23, 2010
I found it useful in event handlers to know the index if the selected option and the option element itself. I did this using a simple change:
@@ -339,8 +339,11 @@ $.widget("ui.selectmenu", {
this._prevChar[0] = C;
},
_uiHash: function(){
+ var index = this.value();
return {
- value: this.value()
+ index: index,
+ option: $("option", this.element).get(index),
+ value: this.element[0].value
};
},
open: function(event){
scottjehl said
at 11:29 am on Feb 23, 2010
This looks like a good idea to me, but the "option" property seems like it should be named a bit more specifically. selectedOption maybe? Also should index be selectedIndex?
Wichert Akkerman said
at 11:32 am on Feb 23, 2010
I have no strong opinion on the naming. selectedOption and selectedIndex work for me.
cbono said
at 7:31 am on Mar 23, 2010
I like this project a lot. Something that would really help me is a little better control over the contents of the ui-selectmenu-status element. Specifically, I want the ui-selectmenu-status to show an icon without text (full text of all options available when the menu is opened). If the text content were in a separate SPAN (like the icon in ui-selectmenu-item-icon), then I could simply turn it off in CSS.
As it stands now, I have to use jQuery to target the text node and remove it.
Kaleb Sturgill said
at 9:02 am on Mar 29, 2010
To make the select menu go up instead of down when at the bottom of the page you can add replace the _refreshPosition function with this below:
_refreshPosition: function(){
//set left value
this.list.css('left', this.newelement.offset().left);
//set top value
var menuTop = this.newelement.offset().top;
var scrolledAmt = this.list[0].scrollTop;
this.list.find('li:lt('+this._selectedIndex()+')').each(function(){
scrolledAmt -= $(this).outerHeight();
});
if(this.newelement.is('.'+this.widgetBaseClass+'-popup')){
menuTop+=scrolledAmt;
}
else {
if(menuTop + this.list.height() > $(window).height()){
menuTop = menuTop - this.list.height();
}
else{
menuTop += this.newelement.height();
}
}
this.list.css('top', menuTop);
}
sasquatch said
at 9:40 am on May 1, 2010
The select menu doesn't work properly with jQuery UI 1.8. You can test it, the default "popup" style menu's width is not right , and almost all menus are closing immediately when you click on the select menu name.
pluggy said
at 8:02 am on May 4, 2010
I made a two minor changes to the plugin so that it
* it now works with jquery.ui 1.8
* it works with group names that contain whitespace
How can I submit my changes?
Richard D. Worth said
at 8:52 am on May 4, 2010
Since moving jQuery UI to GitHub, we're no longer managing the code that was in the svn /branches/labs/. To share changes to any code that was in there, such as this selectmenu plugin, you can
1. Create your own project on googlecode, release the selectmenu plugin with your changes as your own selectmenu plugin
2. Create your own project on GitHub, release the selectmenu plugin with your changes as your own selectmenu plugin
3. Fork the jQuery UI github repo. Create a selectmenu branch. Add the selectmenu plugin files from /branches/labs/. Commit your changes to the selectmenu branch in your fork.
Whichever way you go, feel free to post a link to your changes on this page or in the comments. Thanks!
fnagel said
at 10:02 am on May 10, 2010
The changes seem not to be uploaded to svn, could you please provide your changes in a zip or something? Thanks!
Pierre.H A said
at 10:26 am on Jul 27, 2010
Hello i would be interested by your changes, could you share your sources ?
I would like to add the possibility to create selectmenu from Array...
Pierre.H A said
at 12:09 pm on Jul 27, 2010
Well after long search on google I've find it.
It's on GitHub in a new branch, but i will probably not have the time to work on it before the 20 August.
Charles Choiniere said
at 2:11 pm on May 9, 2010
A direction parameter would be nice to force the menu to always drop down if you have say a menu that is close to the top of the window or bottom for example.
fnagel said
at 5:39 am on May 10, 2010
Would be pretty cool if this plugins could use an unordered list as a start.
mayur said
at 4:15 am on Jul 28, 2010
I am using ui.selectmenu inside colorbox.
It works fine with below two combinations:
jQuery 1.3.2 and colorbox 1.3.8
jQuery 1.4.2 and colorbox 1.3.0
It does't work with the versions: jQuery 1.4.2 and colorbox 1.3.8
The problem is destroy method of ui.selectmenu call immediately after init method undesirably. So ui effect seen for moment.
I fix this by adding custom destroy method and call it when required.
// ui.selectmenu.js
..........
destroy: function() {
return;
},
// added function for custom destroy method
mydestroy: function() {
this.element.removeData(this.widgetName)
.removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled')
.removeAttr('aria-disabled');
//unbind click on label, reset its for attr
$('label[for='+this.newelement.attr('id')+']')
.attr('for',this.element.attr('id'))
.unbind('click');
this.newelement.remove();
this.list.remove();
this.element.show();
},
.........
mayur said
at 4:18 am on Jul 28, 2010
The problem occured only on when colorbox resize method called. Otherwise it is fine with ui.selectmenu.
aurelien gerits said
at 2:34 am on Aug 3, 2010
Hello,
jQuery ui selectmenu is not working properly with ui dialog.
What can i do to retrieve a newer version of jQuery ui selectmenu.
Thanks :)
Drew said
at 11:28 am on Aug 20, 2010
I am noticing issues with ui dialog as well.
Tauren Mills said
at 2:18 am on Sep 2, 2010
Yes indeed. It doesn't look like it works in a dialog.
Tauren Mills said
at 3:21 am on Sep 2, 2010
Actually, it wasn't hard to get it working. Simply add a z-index greater than your dialog to .ui-selectmenu-menu. For instance:
.ui-selectmenu-menu { z-index: 9999; }
The reason the problem looked more complex to me is that my dialog contains hidden divs which contain selects (my dialog is a multi-step wizard). This is an issue because when a containing element (such as my wizard step divs) is hidden (display: none), then $("select").width() will return 0 for any selects inside the hidden element. Thus my selectmenus were zero width and didn't appear to be working.
I was able to find several fixes to the problem, but the easiest is probably to add a width option when calling selectmenu. Another option is to not use display: none, and use text-indent: -9999 or some other method of hiding content, but that still keeps it "visible" for rendering widths to be calculated.
The solution I ended up using was to style my selects with .dialog select { width: 100%; } since they are all in table cells anyway, and to hide my divs AFTER calling selectmenu instead of putting diplay:none in my CSS.
I hope this helps others...
Mat Marlow said
at 12:22 am on Aug 6, 2010
Hi all,
I would love to see this menu taking advantage of optgroups a little more to organise large menus and make them more usable. For instance, optgroups could act as parents for fly-out or even accordion style hierarchies, making large menus much easier to use. A good example of this would be a typically large Country menu which could be grouped by Continent. I guess we may be able to achieve a certain amount with CSS for flyouts but perhaps ui.accordion could be used for the other option?
Thanks
PS. loving this widget :)
fnagel said
at 6:06 pm on Aug 6, 2010
Finlay there are some good news ;-)
I opened a repo at GitHub to push further development of this plugin. So far the following bugfixes are included:
- working with jQuery 1.4.x and jQuery UI 1.8.x
- problems with positioning
- problems with whitespaces in optgroup
Please add bugs and feature requests to the GitHub issues Tracker: http://github.com/fnagel/jquery-ui/issues
fnagel said
at 6:12 pm on Aug 6, 2010
Forgot link to repo ;-) Please see my jQuery UI branch "selectmenu":
http://github.com/fnagel/jquery-ui/tree/selectmenu
Download repo, open: demo/selectmenu/index.html
Tauren Mills said
at 11:29 pm on Sep 1, 2010
This meets 95% of my needs in it's current form, great work!
The main problem I have is that I need to display images that I cannot specify in advance in my CSS file. For instance, I need to show a drop down list of people, with their profile photo next to their name. Currently, I'm displaying their Gravatar (http://gravatar.com), so I need to display an image like the following:
<img src="http://www.gravatar.com/avatar/ba0c49b9807f496ba4d567700b0cf2fe?d=monsterid&r=g&s=25">
Is this possible in the current version? If so how? If not, it would be a valuable feature.
Tauren Mills said
at 11:30 pm on Sep 1, 2010
That URL didn't post right. Here it is again:
http://www.gravatar.com/avatar/ba0c49b9807f496ba4d567700b0cf2fe?d=monsterid&r=g&s=25
Tauren Mills said
at 2:00 am on Sep 2, 2010
I just made some enhancements in my fork on github. It is more of a hack than anything, I'm sure there are much better ways to do this. But I needed to get something working for a project. Maybe it will help, or at lease be useful to someone else.
Basically, if your option tag has a title attribute, and you have the icons option enabled, then the value of the option title attribute will be used as the background image.
I've added an example of using it to the selectmenu demo page:
http://github.com/tauren/jquery-ui/blob/selectmenu/demos/selectmenu/default.html
Here is the updated source:
http://github.com/tauren/jquery-ui/blob/selectmenu/ui/jquery.ui.selectmenu.js
You don't have permission to comment on this page.