node-focusmanager-1.mustache revision 5f9cae5c825d76bdc95b78301e460a46ec5fbdf4
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<div class="intro">
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveThis example illustrates how to create an accessible toolbar using the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveFocus Manager Node Plugin and Node's support for the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<a href="http://www.w3.org/TR/wai-aria/">WAI-ARIA Roles and States</a>.
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<div class="example">
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove <style scoped>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove .yui3-toolbar {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border: solid 1px #999;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-color: #ccc;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove margin: .25em;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove overflow: auto;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove .yui3-toolbar-button {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove display: inline-block;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-width: 1px 0;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-style: solid;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-color: #808080;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-color: #dfdfdf;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove margin: .25em;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove font-size: 85%; /* 11px */
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove .first-child {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove margin-left: .5em;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove .yui3-toolbar-button span {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove display: inline-block;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-width: 0 1px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-style: solid;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-color: #808080;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove margin: 0 -1px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *position: relative; /* Necessary to get negative margins working in IE */
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *left: -1px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove .yui3-toolbar-button span span {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove display: inline-block;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border: solid 1px #b6b6b6;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *position: static;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove .yui3-toolbar-button input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border: none;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove padding: 4px 4px 4px 24px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *overflow: visible; /* Remove superfluous padding for IE */
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background: transparent url({{componentAssets}}/icons.png) no-repeat;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove #add-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -102px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -100px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove #edit-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -78px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -76px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove #print-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -54px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -52px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove #open-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -30px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -28px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove #delete-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -126px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -124px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove #save-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -6px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -4px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove /* Augment the browser's default styling of the focus state by changing the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background color of the button when it is focused. */
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove .yui3-toolbar-button input.focus {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-color: #B3D4FF;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove {{>node-focusmanager-1-source}}
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<h2>Setting Up the HTML</h2>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveStart with a set of <code><input></code> elements. For the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovepurpose of this example, the <code>type</code> attribute of each
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovebutton will be set to a value of "button" since they won't be responsible for
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovesubmitting a form. Each <code><input></code> is wrapped by two
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<code><span></code>s that serve as decorator elements used to style
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveeach button with rounded corners.
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<div id="toolbar-1" class="yui3-toolbar">
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove <span id="add-btn" class="yui3-toolbar-button first-child"><span><span><input type="button" name="btn-add" value="Add"></span></span></span>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove <span id="edit-btn" class="yui3-toolbar-button"><span><span><input type="button" name="btn-edit" value="Edit"></span></span></span>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove <span id="print-btn" class="yui3-toolbar-button"><span><span><input type="button" name="btn-print" value="Print"></span></span></span>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove <span id="delete-btn" class="yui3-toolbar-button"><span><span><input type="button" name="btn-delete" value="Delete"></span></span></span>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove <span id="open-btn" class="yui3-toolbar-button"><span><span><input type="button" name="btn-open" value="Open"></span></span></span>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove <span id="save-btn" class="yui3-toolbar-button"><span><span><input type="button" name="btn-save" value="Save"></span></span></span>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<h2>Setting Up the CSS</h2>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveNext, each button in the toolbar is styled with rounded corners using a
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovecombination of the CSS <code>border</code> property along with the use of
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovenegative margins. An icon is added to each button using a background image.
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveFollowing the advice of the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<a href="http://developer.yahoo.com/performance/rules.html">Exceptional Performance team</a>,
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovethis example uses the technique of
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<a href="http://www.alistapart.com/articles/sprites">CSS Sprites</a>,
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovecombining all of the icons for each button into a single image to reduce
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveHTTP requests.
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove.yui3-toolbar {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border: solid 1px #999;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-color: #ccc;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove margin: .25em;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove overflow: auto;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove.yui3-toolbar-button {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove display: inline-block;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-width: 1px 0;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-style: solid;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-color: #808080;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-color: #dfdfdf;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove margin: .25em;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove font-size: 85%; /* 11px */
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove.first-child {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove margin-left: .5em;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove.yui3-toolbar-button span {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove display: inline-block;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-width: 0 1px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-style: solid;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border-color: #808080;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove margin: 0 -1px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *position: relative; /* Necessary to get negative margins working in IE */
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *left: -1px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove.yui3-toolbar-button span span {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove display: inline-block;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border: solid 1px #b6b6b6;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *position: static;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove.yui3-toolbar-button input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove border: none;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove padding: 4px 4px 4px 24px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *overflow: visible; /* Remove superfluous padding for IE */
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background: transparent url({{componentAssets}}/icons.png) no-repeat;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove#add-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -102px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -100px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove#edit-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -78px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -76px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove#print-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -54px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -52px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove#open-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -30px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -28px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove#delete-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -126px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -124px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove#save-btn input {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-position: 4px -6px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove *background-position: 4px -4px;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<h2>Initializing the Focus Manager</h2>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveWith the toolbar markup and CSS in place, retrieve the Node instance
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groverepresenting the toolbar (<code><div id="toolbar-1"></code>)
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveand call the <a href="{{apiDocs}}/classes/Node.html#method_plug"><code>plug</code></a>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovepassing in a reference to the Focus Manager Node Plugin as the first argument,
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveand a collection of configuration attributes as the second argument.
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveThe Focus Manager's
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<a href="{{apiDocs}}/classes/plugin.NodeFocusManager.html#config_descendants"><code>descendants</code></a>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveattribute is set to a value of "input", so that only one button in the toolbar
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveis in the browser's default tab flow. This allows users navigating via the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovekeyboard to use the tab key to quickly move into and out of the toolbar. Once
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovethe toolbar has focus, the user can move focus among each button using the left
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveand right arrows keys, as defined by the value of the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<a href="{{apiDocs}}/classes/plugin.NodeFocusManager.html#config_keys"><code>keys</code></a>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveattribute. Lastly, the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<a href="{{apiDocs}}/classes/plugin.NodeFocusManager.html#config_focusClass"><code>focusClass</code></a>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveattribute is used to apply a class of <code>focus</code> to each
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<code><input></code> when it is focused, making it easy to style the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grovefocused state in all browsers.
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveYUI().use("node-focusmanager", function (Y) {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove // Retrieve the Node instance representing the toolbar
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove // (<div id="toolbar">) and call the "plug" method
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove // passing in a reference to the Focus Manager Node Plugin.
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove var toolbar = Y.one("#toolbar-1");
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove descendants: "input",
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove keys: { next: "down:39", // Right arrow
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove previous: "down:37" }, // Left arrow
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove focusClass: "focus",
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove circular: true
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove // Set the ARIA "role" attribute of the Node instance representing the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove // toolbar to "toolbar" to improve the semantics of the markup for
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove // users of screen readers.
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove toolbar.set("role", "toolbar");
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove // Listen for the click event on each button via the use of the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove // "delegate" method
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove toolbar.delegate("click", function (event) {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove alert("You clicked " + this.one("input").get("value"));
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove }, ".yui3-toolbar-button");
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<h2>Styling Focus</h2>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan GroveTo augment the browser's default styling of the focused state define a CSS
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Groveselector that adds a background color to the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove/* Augment the browser's default styling of the focus state by changing the
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background color of the button when it is focused. */
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove.yui3-toolbar-button input.focus {
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove background-color: #B3D4FF;
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove<h2>Complete Example Source</h2>
5f9cae5c825d76bdc95b78301e460a46ec5fbdf4Ryan Grove{{>node-focusmanager-1-source}}