Tabpanel Navigation Menu
Combobox Example 3: aria-autocomplete = 'list'
Example Notes
This is example implements a combobox widget with aria-autocomplete="list". Focus remains on the edit box while the user manipulates the list. activedescendant is used to tell assistive technologies which list option is currently selected. For clarity, this example was designed not to update the edit box until the user makes a choice from the list.
Keyboard Shortcuts
- Enter: Select highlighted option and close the list box. If list box is closed, opens the list box.
- Escape: Close list box without changing the combobox value (e.g. no selection is made).
- Up Arrow: Moves upward in list. If the list box is closed, this does not select the highlighted list option.
- Down Arrow: Moves downward in list. If the list box is closed, this does not select the highlighted list option.
- Home: If the list box is open, moves to first option in list.
- End: If the list box is open, moves to last option in list.
- Tab: Select highlighted option and close list box. Focus moves to the next focusable element in page.
- Shift+Tab: Same as tab key except focus moves to previous focusable item in page.
- Ctrl + Up Arrow/Down Arrow: Open or close the list box.
Note: Opera does not propagate alt key modifer events to the web page. Alt+Arrow key combinations will not work in Opera.
ARIA Roles and Properties
-
Roles:
role="application"
role="combobox"
- States and properties:
aria-expanded
aria-labelledby
aria-owns
HTML Source Code
Show HTML Source Code: combobox3.inc
<div role="application" tabindex="-1">
<form autocomplete="off">
<div id="cb1" class="cb">
<div class="cb_label"><label id="cb1-label" for="cb1-edit">State</label>:</div>
<input id="cb1-edit" class="cb_edit" type="text"
tabindex="0"
role="combobox"
aria-labelledby="cb1-label"
aria-autocomplete="list"
aria-owns="cb1-list"
aria-readonly="true"
aria-activedescendant="cb1-opt16"/>
<div id="cb1-button-label" class="hidden">Open list of states</div>
<button id="cb1-button" class="cb_button" aria-labelledby="cb1-button-label" aria-controls="cb1-list" tabindex="-1">
<img src="images/button-arrow-down.png" alt="Open or close the list box" />
</button>
<ul id="cb1-list" class="cb_list" tabindex="-1" aria-expanded="true">
<li id="cb1-opt1" role="option" class="cb_option" role="listitem" tabindex="-1">Alabama</li>
<li id="cb1-opt2" role="option" class="cb_option" role="listitem" tabindex="-1">Alaska</li>
<li id="cb1-opt3" role="option" class="cb_option" role="listitem" tabindex="-1">American Samoa</li>
<li id="cb1-opt4" role="option" class="cb_option" role="listitem" tabindex="-1">Arizona</li>
<li id="cb1-opt5" role="option" class="cb_option" role="listitem" tabindex="-1">Arkansas</li>
<li id="cb1-opt6" role="option" class="cb_option" role="listitem" tabindex="-1">California</li>
<li id="cb1-opt7" role="option" class="cb_option" role="listitem" tabindex="-1">Colorado</li>
<li id="cb1-opt8" role="option" class="cb_option" role="listitem" tabindex="-1">Connecticut</li>
<li id="cb1-opt9" role="option" class="cb_option" role="listitem" tabindex="-1">Delaware</li>
<li id="cb1-opt10" role="option" class="cb_option" role="listitem" tabindex="-1">District of Columbia</li>
<li id="cb1-opt11" role="option" class="cb_option" role="listitem" tabindex="-1">Florida</li>
<li id="cb1-opt12" role="option" class="cb_option" role="listitem" tabindex="-1">Georgia</li>
<li id="cb1-opt13" role="option" class="cb_option" role="listitem" tabindex="-1">Guam</li>
<li id="cb1-opt14" role="option" class="cb_option" role="listitem" tabindex="-1">Hawaii</li>
<li id="cb1-opt15" role="option" class="cb_option" role="listitem" tabindex="-1">Idaho</li>
<li id="cb1-opt16" role="option" class="cb_option selected" role="listitem" tabindex="-1">Illinois</li>
<li id="cb1-opt17" role="option" class="cb_option" role="listitem" tabindex="-1">Indiana</li>
<li id="cb1-opt18" role="option" class="cb_option" role="listitem" tabindex="-1">Iowa</li>
<li id="cb1-opt19" role="option" class="cb_option" role="listitem" tabindex="-1">Kansas</li>
<li id="cb1-opt20" role="option" class="cb_option" role="listitem" tabindex="-1">Kentucky</li>
<li id="cb1-opt21" role="option" class="cb_option" role="listitem" tabindex="-1">Louisiana</li>
<li id="cb1-opt22" role="option" class="cb_option" role="listitem" tabindex="-1">Maine</li>
<li id="cb1-opt23" role="option" class="cb_option" role="listitem" tabindex="-1">Maryland</li>
<li id="cb1-opt24" role="option" class="cb_option" role="listitem" tabindex="-1">Massachusetts</li>
<li id="cb1-opt25" role="option" class="cb_option" role="listitem" tabindex="-1">Michigan</li>
<li id="cb1-opt26" role="option" class="cb_option" role="listitem" tabindex="-1">Minnesota</li>
<li id="cb1-opt27" role="option" class="cb_option" role="listitem" tabindex="-1">Mississippi</li>
<li id="cb1-opt28" role="option" class="cb_option" role="listitem" tabindex="-1">Missouri</li>
<li id="cb1-opt29" role="option" class="cb_option" role="listitem" tabindex="-1">Montana</li>
<li id="cb1-opt30" role="option" class="cb_option" role="listitem" tabindex="-1">Nebraska</li>
<li id="cb1-opt31" role="option" class="cb_option" role="listitem" tabindex="-1">Nevada</li>
<li id="cb1-opt32" role="option" class="cb_option" role="listitem" tabindex="-1">New Hampshire</li>
<li id="cb1-opt33" role="option" class="cb_option" role="listitem" tabindex="-1">New Jersey</li>
<li id="cb1-opt34" role="option" class="cb_option" role="listitem" tabindex="-1">New Mexico</li>
<li id="cb1-opt35" role="option" class="cb_option" role="listitem" tabindex="-1">New York</li>
<li id="cb1-opt36" role="option" class="cb_option" role="listitem" tabindex="-1">North Carolina</li>
<li id="cb1-opt37" role="option" class="cb_option" role="listitem" tabindex="-1">North Dakota</li>
<li id="cb1-opt38" role="option" class="cb_option" role="listitem" tabindex="-1">Northern Marianas Islands</li>
<li id="cb1-opt39" role="option" class="cb_option" role="listitem" tabindex="-1">Ohio</li>
<li id="cb1-opt40" role="option" class="cb_option" role="listitem" tabindex="-1">Oklahoma</li>
<li id="cb1-opt41" role="option" class="cb_option" role="listitem" tabindex="-1">Oregon</li>
<li id="cb1-opt42" role="option" class="cb_option" role="listitem" tabindex="-1">Pennsylvania</li>
<li id="cb1-opt43" role="option" class="cb_option" role="listitem" tabindex="-1">Puerto Rico</li>
<li id="cb1-opt44" role="option" class="cb_option" role="listitem" tabindex="-1">Rhode Island</li>
<li id="cb1-opt45" role="option" class="cb_option" role="listitem" tabindex="-1">South Carolina</li>
<li id="cb1-opt47" role="option" class="cb_option" role="listitem" tabindex="-1">South Dakota</li>
<li id="cb1-opt48" role="option" class="cb_option" role="listitem" tabindex="-1">Tennessee</li>
<li id="cb1-opt49" role="option" class="cb_option" role="listitem" tabindex="-1">Texas</li>
<li id="cb1-opt50" role="option" class="cb_option" role="listitem" tabindex="-1">Utah</li>
<li id="cb1-opt51" role="option" class="cb_option" role="listitem" tabindex="-1">Vermont</li>
<li id="cb1-opt52" role="option" class="cb_option" role="listitem" tabindex="-1">Virginia</li>
<li id="cb1-opt53" role="option" class="cb_option" role="listitem" tabindex="-1">Virgin Islands</li>
<li id="cb1-opt54" role="option" class="cb_option" role="listitem" tabindex="-1">Washington</li>
<li id="cb1-opt55" role="option" class="cb_option" role="listitem" tabindex="-1">West Virginia</li>
<li id="cb1-opt56" role="option" class="cb_option" role="listitem" tabindex="-1">Wisconsin</li>
<li id="cb1-opt57" role="option" class="cb_option" role="listitem" tabindex="-1">Wyoming</li>
</ul>
</div>
</form>
</div>
Javascript Source Code
Show Javascript Source Code: combobox3.js
<script type="text/javascript">
var g_combo = null; // set to active combobox for blur function
$(document).ready(function() {
var cb1 = new combobox('cb1', false);
}); // end ready
//
// keyCodes() is an object to contain keycodes needed for the application
//
function keyCodes() {
// Define values for keycodes
this.backspace = 8;
this.tab = 9;
this.enter = 13;
this.esc = 27;
this.space = 32;
this.pageup = 33;
this.pagedown = 34;
this.end = 35;
this.home = 36;
this.up = 38;
this.down = 40;
this.del = 46;
} // end keyCodes
//
// Function combobox() is a class for an ARIA-enabled combobox widget
//
// @param (id string) id is the id of the div containing the combobox. Div must have role="combobox".
//
// @param (editable boolean) editable is true if the edit box should be editable; false if read-only.
//
// @return N/A
//
function combobox(id, editable) {
// Define the object properties
this.$id = id; // The jQuery object of the div containing the combobox
this.editable = editable; // True if the edit box is editable
this.keys = new keyCodes();
// Store jQuery objects for the elements of the combobox
this.$edit = $('#' + id + '-edit'); // The jQuery object of the edit box
this.$button = $('#' + id + '-button'); // The jQuery object of the button
this.$list = $('#' + id + '-list'); // The jQuery object of the option list
this.$options = this.$list.find('li'); // An array of jQuery objects for the combobox options
this.$selected; // the current value of the combobox
this.$focused; // the currently selected option in the combo list
this.timer = null; // stores the close list timer that is set when combo looses focus
// Initalize the combobox
this.init();
// bind event handlers for the widget
this.bindHandlers();
} // end combobox constructor
//
// Function init() is a member function to initialize the combobox elements. Hides the list
// and sets ARIA attributes
//
// @return N/A
//
combobox.prototype.init = function() {
// Hide the list of options
this.$list.hide().attr('aria-expanded', 'false');
// If the edit box is to be readonly, aria-readonly must be defined as true
if (this.editable == false) {
this.$edit.attr('aria-readonly', 'true');
}
// Set initial value for the edit box
this.$selected = this.$options.filter('.selected');
if (this.$selected.length > 0) {
this.$edit.val(this.$selected.text());
}
} // end initCombo()
//
// Function bindHandlers() is a member function to bind event handlers for the combobox elements
//
// @return N/A
//
combobox.prototype.bindHandlers = function() {
var thisObj = this;
///////////////// bind handlers for the button /////////////////////////
this.$button.click(function(e) {
return thisObj.handleButtonClick($(this), e);
});
this.$button.mouseover(function(e) {
return thisObj.handleButtonMouseOver($(this), e);
});
this.$button.mouseout(function(e) {
return thisObj.handleButtonMouseOut($(this), e);
});
this.$button.mousedown(function(e) {
return thisObj.handleButtonMouseDown($(this), e);
});
this.$button.mouseup(function(e) {
return thisObj.handleButtonMouseUp($(this), e);
});
///////////////// bind listbox handlers /////////////////////////
this.$options.click(function(e) {
return thisObj.handleOptionClick($(this), e);
});
this.$list.focus(function(e) {
return thisObj.handleComboFocus($(this), e);
});
this.$list.blur(function(e) {
return thisObj.handleComboBlur($(this), e);
});
this.$options.focus(function(e) {
return thisObj.handleComboFocus($(this), e);
});
this.$options.blur(function(e) {
return thisObj.handleComboBlur($(this), e);
});
///////////////// bind editbox handlers /////////////////////////
this.$edit.keydown(function(e) {
return thisObj.handleEditKeyDown($(this), e);
});
this.$edit.keypress(function(e) {
return thisObj.handleEditKeyPress($(this), e);
});
this.$edit.blur(function(e) {
return thisObj.handleComboBlur($(this), e);
});
} // end bindHandlers()
//
// Function isOpen() is a member function to get the current state of the list box
//
// @return (boolean) returns true if list box is open; false if it is not
//
combobox.prototype.isOpen = function() {
if (this.$list.attr('aria-expanded') == 'true') {
return true;
}
else {
return false;
}
} // end isOpen
//
// Function closeList() is a member function to close the list box if it is open
//
// @param (restore booleam) restore is true if function should restore higlight to stored list selection
//
// @return N/A
//
combobox.prototype.closeList = function(restore) {
var $curOption = this.$options.filter('.selected');
if (restore == true) {
$curOption = this.$selected;
// remove the selected class from the other list items
this.$options.removeClass('selected');
// add selected class to the stored selection
$curOption.addClass('selected');
}
this.$list.hide().attr('aria-expanded', 'false');
} // end closeList()
//
// Function openList() is a member function to open the list box if it is closed
//
// @param (restore booleam) restore is true if function should restore higlight to stored list selection
//
// @return N/A
//
combobox.prototype.openList = function(restore) {
var $curOption = this.$options.filter('.selected');
if (restore == true) {
if (this.$selected.length == 0) {
// select the first item
this.selectOption(this.$options.first());
$curOption = this.$selected;
}
else {
$curOption = this.$selected;
}
// remove the selected class from the other list items
this.$options.removeClass('selected');
// add selected class to the stored selection
$curOption.addClass('selected');
}
this.$list.show().attr('aria-expanded', 'true');
// scroll to the currently selected option
this.$list.scrollTop(this.calcOffset($curOption));
} // end openList();
//
// Function toggleList() is a member function to toggle the display of the combobox options.
//
// @param (restore booleam) restore is true if toggle should restore higlight to stored list selection
//
// Return N/A
//
combobox.prototype.toggleList = function(restore) {
if (this.isOpen() == true) {
this.closeList(restore);
}
else {
this.openList(restore);
}
} // end toggleList()
//
// Function selectOption() is a member function to select a new combobox option.
// The jQuery object for the new option is stored and the selected class is added
//
// @param ($id object) $id is the jQuery object of the new option to select
//
// @return N/A
//
combobox.prototype.selectOption = function($id) {
// If there is a selected option, remove the selected class from it
if (this.$selected.length > 0) {
this.$selected.removeClass('selected');
}
// add the selected class to the new option
$id.addClass('selected');
// set active descendant for the new option
this.$edit.attr('aria-activedescendant', $id.attr('id'));
// store the newly selected option
this.$selected = $id;
// update the edit box
this.$edit.val($id.text());
} // end selectOption
//
// Function calcOffset() is a member function to calculate the pixel offset of a list option from the top
// of the list
//
// @param ($id obj) $id is the jQuery object of the option to scroll to
//
// @return (integer) returns the pixel offset of the option
//
combobox.prototype.calcOffset = function($id) {
var offset = 0;
var selectedNdx = this.$options.index($id);
for (var ndx = 0; ndx < selectedNdx; ndx++) {
offset += this.$options.eq(ndx).outerHeight();
}
return offset;
} // end calcOffset
//
// Function handleButtonClick() is a member function to consume button click events. This handler prevents
// clicks on the button from reloading the page. This could also be done by adding 'onclick="false";' to the
// button HTML markup.
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) returns false;
//
combobox.prototype.handleButtonClick = function($id, e) {
e.stopPropagation();
return false;
} // end handleButtonClick();
//
// Function handleButtonMouseOver() is a member function to process button mouseover events
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) returns false;
//
combobox.prototype.handleButtonMouseOver = function($id, e) {
// change the button image to reflect the highlight state
$id.find('img').attr('src', 'images/button-arrow-down-hl.png');
e.stopPropagation();
return false;
} // end handleButtonMouseOver();
//
// Function handleButtonMouseOut() is a member function to process button mouseout events
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) returns false;
//
combobox.prototype.handleButtonMouseOut = function($id, e) {
// reset image to normal state
$id.find('img').attr('src', 'images/button-arrow-down.png');
e.stopPropagation();
return false;
} // end handleButtonMouseOut();
//
// Function handleButtonMouseDown() is a member function to process button mousedown events
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) returns false;
//
combobox.prototype.handleButtonMouseDown = function($id, e) {
// change the button image to reflect the pressed state
$id.find('img').attr('src', 'images/button-arrow-down-pressed-hl.png');
// toggle the display of the option list
this.toggleList(true);
// Set focus on the edit box
this.$edit.focus();
e.stopPropagation();
return false;
} // end handleButtonMouseDown();
//
// Function handleButtonMouseUp() is a member function to process button mouseup events
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) returns false;
//
combobox.prototype.handleButtonMouseUp = function($id, e) {
// reset button image
$id.find('img').attr('src', 'images/button-arrow-down-hl.png');
e.stopPropagation();
return false;
} // end handleButtonMouseUp();
//
// Function handleEditKeyDown() is a member function to process keydown events for
// the edit box.
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) Returns false if consuming; true if not processing
//
combobox.prototype.handleEditKeyDown = function($id, e) {
var $curOption = this.$options.filter('.selected');
var curNdx = this.$options.index($curOption);
if (e.altKey && (e.keyCode == this.keys.up || e.keyCode == this.keys.down)) {
this.toggleList(true);
e.stopPropagation();
return false;
}
switch (e.keyCode) {
case this.keys.backspace:
case this.keys.del: {
// prevent the edit box from being changed
this.$edit.val(this.$selected.text());
e.stopPropagation();
return false;
}
case this.keys.tab: {
// store the current selection
this.selectOption($curOption);
if (this.isOpen() == true) {
// Close the option list
this.closeList(false);
}
// allow tab to propagate
return true;
}
case this.keys.esc: {
// Do not change combobox value
if (this.isOpen() == true) {
// Close the option list
this.closeList(true);
}
e.stopPropagation();
return false;
}
case this.keys.enter: {
if (this.isOpen() == true) {
// store the current selection
this.selectOption($curOption);
// Close the option list
this.closeList(false);
}
else {
this.openList(false);
}
e.stopPropagation();
return false;
}
case this.keys.up: {
// move to the previous item in the list
// if the list is expanded and this isn't the first item
// move to the next item in the list
if (curNdx > 0) {
var $prev = this.$options.eq(curNdx - 1);
if (this.isOpen() == true) {
// remove the selected class from the current selection
$curOption.removeClass('selected');
// Add the selected class to the new selection
$prev.addClass('selected');
// Set activedescendent for new option
this.$edit.attr('aria-activedescendant', $prev.attr('id'));
// scroll the list window to the new option
this.$list.scrollTop(this.calcOffset($prev));
}
else {
// store the new selection
this.selectOption($prev);
}
}
e.stopPropagation();
return false;
}
case this.keys.down: {
// if the list is expanded and there are more items,
// move to the next item in the list
if (curNdx < this.$options.length - 1) {
var $next = this.$options.eq(curNdx + 1);
if (this.isOpen() == true) {
// remove the selected class from the current selection
$curOption.removeClass('selected');
// Add the selected class to the new selection
$next.addClass('selected');
// Set activedescendent for new option
this.$edit.attr('aria-activedescendant', $next.attr('id'));
// scroll the list window to the new option
this.$list.scrollTop(this.calcOffset($next));
}
else {
// store the new selection
this.selectOption($next);
}
}
e.stopPropagation();
return false;
}
case this.keys.home: {
// select the first list item if the list is open
if (this.isOpen() == true) {
var $first = this.$options.first();
// remove the selected class from the current selection
$curOption.removeClass('selected');
// Add the selected class to the new selection
$first.addClass('selected');
// scroll the list window to the new option
this.$list.scrollTop(0);
// Set activedescendent for new option
this.$edit.attr('aria-activedescendant', $first.attr('id'));
}
e.stopPropagation();
return false;
}
case this.keys.end: {
// select the last list item if the list is open
if (this.isOpen() == true) {
var $last = this.$options.last();
// remove the selected class from the current selection
$curOption.removeClass('selected');
// Add the selected class to the new selection
$last.addClass('selected');
// scroll the list window to the new option
this.$list.scrollTop(this.calcOffset($last));
// Set activedescendent for new option
this.$edit.attr('aria-activedescendant', $last.attr('id'));
}
e.stopPropagation();
return false;
}
}
return true;
} // end handleEditKeyDown()
//
// Function handleEditKeyPress() is a member function to process keypress events for
// the edit box. Needed for browsers that use keypress events to manipulate the window.
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) Returns false if consuming; true if not processing
//
combobox.prototype.handleEditKeyPress = function($id, e) {
var curNdx = this.$options.index($id);
if (e.altKey && (e.keyCode == this.keys.up || e.keyCode == this.keys.down)) {
e.stopPropagation();
return false;
}
switch(e.keyCode) {
case this.keys.esc:
case this.keys.enter: {
e.stopPropagation();
return false;
}
}
return true;
} // end handleOptionKeyPress()
//
// Function handleOptionClick() is a member function to process click events for
// the combobox.
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) Returns false
//
combobox.prototype.handleOptionClick = function($id, e) {
// select the clicked item
this.selectOption($id);
// set focus on the edit box
//this.$edit.focus();
// close the list
this.closeList(false);
e.stopPropagation();
return false;
} // end handleOptionClick()
//
// Function handleComboFocus() is a member function to process focus events for
// the list box
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) Returns true
//
combobox.prototype.handleComboFocus = function($id, e) {
if (g_combo != null) {
window.clearTimeout(g_combo.timer);
}
// Set focus on the edit box
this.$edit.focus();
return true;
} // end handleComboFocus()
//
// Function handleComboBlur() is a member function to process blur events for
// the combobox
//
// @param (e object) e is the event object associated with the event
//
// @param ($id object) $id is the jQuery object for the element firing the event
//
// @return (boolean) Returns true
//
combobox.prototype.handleComboBlur = function($id, e) {
// store the currently selected value
this.$selected = this.$options.filter('.selected');
// update the edit box
this.$edit.val(this.$selected.text());
g_combo = this;
// close the list box
if (this.isOpen() == true) {
this.timer = window.setTimeout(function() {g_combo.closeList(false);}, 40);
}
return true;
} // end handleComboBlur()
</script>
CSS Source Code
Show CSS Source Code: combobox3.css
<style type="text/css">
* {
font-family: "Times New Roman,Georgia,Serif";
}
.hidden {
position: absolute;
top: -20em;
left: -200em;
}
.wrapper {
height: 24px;
overflow: auto;
}
.cb {
margin: 20px;
padding: 0;
height: 24px;
display: block;
overflow: visible;
}
.cb_label {
margin: 0;
padding: 2px;
width: 45px;
font-weight: bold;
float: left;
display: inline;
}
.cb_edit {
margin: 0;
padding: 2px 3px;
width: 240px;
height: 18px;
border: 1px solid black;
font-size: 1em;
float: left;
display: inline;
}
.cb_button {
margin: 0;
padding: 0;
height: 24px;
width: 24px;
border: 1px solid black;
background-color: #999;
float: left;
display: inline;
text-align: center;
}
button.cb_button img {
margin: 0;
padding: 0;
height: 22px;
width: 22px;
position: relative;
top: -1px;
left: -3px;
}
.cb_list {
clear: both;
list-style: none;
padding: 0;
margin: 0;
margin-left: 49px;
border: 1px solid black;
width: 246px;
height: 200px;
overflow: auto;
background-color: #fff;
position: relative;
z-index: 300;
}
.cb_option {
margin: 0 1px 0 0;
padding: 2px 5px;
}
.selected {
border-top: 1px solid #44e;
border-bottom: 1px solid #44e;
padding: 1px 5px;
background-color: #77a;
color: #fff;
}
.cb_option:hover {
border-top: 1px solid #44e;
border-bottom: 1px solid #44e;
padding: 1px 5px;
font-weight: bold;
background-color: #77f;
color: #fff;
}
</style>
W3C Validation of HTML5