Accessible Hamburger (slide-out) Menu Example
197 |Heavily modified from this Codepen by Marcy Sutton.
198 |├── README.md ├── _config.yml ├── autosuggest └── index.html ├── breadcrumb └── index.html ├── chips └── index.html ├── expand-collapse ├── index.html └── index2.html ├── grid ├── include │ ├── dropdownMenuAlt.js │ ├── jquery-ui-1.8.22.core.min.js │ ├── menuButton.css │ └── style.css └── index.html ├── hamburger └── index.html ├── iconfonts ├── fonts │ ├── icomoon.eot │ ├── icomoon.svg │ ├── icomoon.ttf │ └── icomoon.woff ├── icon-fonts.css ├── images │ ├── question-circle.png │ ├── question-circle2.png │ └── question-circle3.png └── index.html ├── menu-button ├── CSUN 2013 Preso - ARIA widget.pptx ├── css │ ├── base.css │ ├── dropdownMenuAlt.css │ └── reset.css ├── index.html ├── js │ ├── _notes │ │ └── dwsync.xml │ ├── dropdownMenuAlt.js │ ├── dropdownMenuAlt_no_aria.js │ ├── jquery-ui-1.8.22.core.min.js │ └── modernizr-2.0.6.js ├── no_aria.html └── with_aria.html ├── modal ├── CSUN14-Modal-Dialog.pptx ├── modal_demo.html ├── modal_demo2.html └── modal_demo_a.html ├── pagination └── index.html ├── password-mask-toggle └── index.html ├── svg ├── checkmark.svg └── index.html ├── tab-panel ├── index.html └── tab-panel.js ├── tables └── data-table-form.html ├── tile ├── images │ └── placeholder.png └── index.html ├── toggle_switch └── index.html └── transition ├── animation.html └── transition.html /README.md: -------------------------------------------------------------------------------- 1 | # Demos 2 | 3 | Examples of web development/web design patterns with accessibility in mind. 4 | 5 | By Dennis Lembree @dennisl 6 | 7 | - [Autosuggest select dropdown](https://weboverhauls.github.io/demos/autosuggest/) 8 | 9 | - [Breadcrumbs](https://weboverhauls.github.io/demos/breadcrumb/) 10 | 11 | - [Chips (with autosuggest)](https://weboverhauls.github.io/demos/chips/) 12 | 13 | - [Interactive elements within grid layout](https://weboverhauls.github.io/demos/grid/) 14 | 15 | - Expand-Collapse 16 | - Classic expand-collapse [Version 1](https://weboverhauls.github.io/demos/expand-collapse/) - [Version 2](https://weboverhauls.github.io/demos/expand-collapse/index2.html) 17 | - [show/hide using CSS transition](https://weboverhauls.github.io/demos/transition/transition.html) 18 | - [show/hide using CSS animation](https://weboverhauls.github.io/demos/transition/animation.html) 19 | 20 | - Dropdown Menu Button: [No ARIA](https://weboverhauls.github.io/demos/menu-button/no_aria.html) - [with ARIA](https://weboverhauls.github.io/demos/menu-button/with_aria.html) 21 | 22 | - [Hamburger/slide out menu](https://weboverhauls.github.io/demos/hamburger/) 23 | 24 | - [Modal Dialog](https://weboverhauls.github.io/demos/modal/modal_demo2.html) 25 | 26 | - [Pagination](https://weboverhauls.github.io/demos/pagination/) 27 | 28 | - [SVG Test Page](https://weboverhauls.github.io/demos/svg/) 29 | 30 | - [Tab Panel](https://weboverhauls.github.io/demos/tab-panel/) 31 | 32 | - [Table with form element](https://weboverhauls.github.io/demos/tables/data-table-form.html) 33 | 34 | - [Tile/Card](https://weboverhauls.github.io/demos/tile/) 35 | 36 | - [Toggle Switch](https://weboverhauls.github.io/demos/toggle_switch/) 37 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /autosuggest/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |This is a heavily modified version of an accessible autosuggest from Intopia's autosuggest article and code example by Adem Cifcioglu. Changes include:
134 |Selected cities:
132 |Example of an expand-collapse widget with progressive enhancement.
47 | 48 |Filler text. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet.
49 | 50 |More filler text. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet.
56 | 57 | 58 | 59 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /expand-collapse/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |Example of an expand-collapse widget with progressive enhancement.
57 | 58 |Cupcake ipsum dolor sit. Amet chupa chups toffee marzipan muffin marshmallow. Fruitcake candy tiramisu toffee tootsie roll bonbon biscuit jujubes. Fruitcake pie jelly bonbon cake sweet tiramisu donut.
59 | 60 |Chupa chups jelly-o dragée bear claw. Brownie bonbon pudding lollipop. Gingerbread oat cake topping topping. Wafer bonbon chocolate cake. The donuts jujubes toffee marzipan muffin marshmallow.
66 | 67 | 70 | 71 | 72 | 73 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /grid/include/dropdownMenuAlt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileOverview Dropdown menu button widget 3 | * @name PayPal Dropdown Menu Alt 4 | * @author swesthafer, dlembree 5 | */ 6 | 7 | (function() { 8 | "use strict"; 9 | 10 | $.widget("widget.dropdownMenuAlt", { 11 | options: { 12 | showOn: "click" //default show on click. Mouseenter another valid option 13 | }, 14 | _create: function() { 15 | this._getElements(); 16 | this._updateElements(); 17 | this._addListeners(); 18 | }, 19 | // get elements to manipulate and base calculations off of 20 | _getElements: function() { 21 | this.elements = {}; 22 | 23 | // the menu container (div role=menu) 24 | this.elements.container = this.element.find("div:first"); 25 | }, 26 | // add listeners for show/hide the menu 27 | _addListeners: function() { 28 | 29 | // close menu when you click off the dropdownMenu 30 | $("html").bind("click", $.proxy(this.closeMenu, this)); 31 | this.element.bind("click", function (event) { event.stopPropagation(); }); 32 | 33 | // close menu when someone clicks on a link 34 | this.element.find("ul a").on("click", $.proxy(this.closeMenu, this)); 35 | 36 | // toggle the menu open/closed when you click on the link 37 | this.element.find(".menuButton").on(this.options.showOn,$.proxy(function(event) { 38 | event.preventDefault(); 39 | this._toggleMenu(); 40 | }, this)); 41 | 42 | // toggle menu by keyboard when hitting Enter or Space 43 | this.element.find(".menuButton").on("keydown", $.proxy(function(event) { 44 | if (event.keyCode === $.ui.keyCode.ENTER || event.keyCode === $.ui.keyCode.SPACE) { 45 | event.preventDefault(); 46 | this._toggleMenu(); 47 | } 48 | }, this)); 49 | 50 | // bind keyboard events 51 | this.element.bind("keydown", $.proxy(function(event) { 52 | 53 | // close menu by keyboard when hitting Escape or Tab 54 | if (event.keyCode === $.ui.keyCode.TAB || event.keyCode === $.ui.keyCode.ESCAPE) { 55 | this.closeMenu(); 56 | } 57 | 58 | // navigate down 59 | if (event.keyCode === $.ui.keyCode.DOWN) { 60 | event.preventDefault(); 61 | 62 | // navigate if menu is open, otherwise open the menu if it's closed 63 | if (this.elements.container.is(':visible')) { 64 | this.focus('+1'); 65 | } else { 66 | this.openMenu(); 67 | } 68 | } 69 | 70 | // navigate up 71 | if (event.keyCode === $.ui.keyCode.UP) { 72 | event.preventDefault(); 73 | 74 | // navigate if menu is open, otherwise open the menu if it's closed 75 | if (this.elements.container.is(':visible')) { 76 | this.focus('-1'); 77 | } else { 78 | this.openMenu(); 79 | } 80 | } 81 | }, this)); 82 | 83 | // close when another menu opens 84 | $('html').bind('openMenu.dropdownMenu', $.proxy(this.closeMenu, this)); 85 | }, 86 | 87 | // gets a menu item from a given index 88 | getItem: function(index) { 89 | return $(this.element.find('ul li a').parent('li')[index]); 90 | }, 91 | 92 | // gets the index of the focused item 93 | getFocusedIndex: function() { 94 | var focusedIndex; 95 | this.element.find('ul li a').parent('li').each(function(index, item) { 96 | if ($(item).find('a:focus').length) { 97 | focusedIndex = index; 98 | } 99 | if (focusedIndex===undefined) { 100 | focusedIndex = -1; 101 | } 102 | }); 103 | return focusedIndex; 104 | }, 105 | 106 | // focuses on an item (can be an index number or the strings '+1' or '-1') 107 | focus: function(index) { 108 | var item; 109 | var len = this.element.find('ul a').length; 110 | 111 | // get the next available index 112 | if (index === '+1') { 113 | // increment index until we find an enabled item 114 | index = this.getFocusedIndex(); 115 | do { index++; } while (this.getItem(index).hasClass('disabled')); 116 | if (index > len-1 ) { 117 | index = 0; 118 | } 119 | } 120 | else if (index === '-1') { 121 | // decrement index until we find an enabled item 122 | index = this.getFocusedIndex(); 123 | do { index--; } while (this.getItem(index).hasClass('disabled')); 124 | if (index < 0 ) { 125 | index = len-1; 126 | } 127 | } 128 | 129 | // get item using index 130 | item = this.getItem(index); 131 | 132 | // return if no item to select 133 | if (!item.length) { 134 | return; 135 | } 136 | 137 | // set focus 138 | $(item.find('a')[0]).focus(); 139 | 140 | // control tabindex for Firefox and Opera issues 141 | this.element.find('ul:first li a').attr("tabindex", "-1"); 142 | $(item.find('a')[0]).attr("tabindex", "0"); 143 | }, 144 | 145 | // toggles the menu 146 | _toggleMenu: function() { 147 | if (this.element.hasClass('showMenu')) { 148 | this.closeMenu(); 149 | } else { 150 | this.openMenu(); 151 | } 152 | }, 153 | 154 | // add parameters to elements 155 | _updateElements: function() { 156 | this.element.find('a:first').attr("aria-haspopup", "true") 157 | .attr("role", "button"); 158 | this.elements.container.attr("role", "menu") 159 | .attr("aria-hidden", "true"); 160 | this.element.find('div div').attr("role", "presentation"); 161 | this.element.find('ul:first').attr("role", "presentation"); 162 | this.element.find('ul:first li').attr("role", "presentation"); 163 | this.element.find('ul:first li a').attr("role", "menuitem") 164 | .attr("tabindex", "-1"); 165 | }, 166 | 167 | // shows button 168 | showButton: function() { 169 | this.element.addClass('showButton'); 170 | }, 171 | 172 | // hides button 173 | hideButton: function() { 174 | this.element.removeClass('showButton'); 175 | this.closeMenu(); 176 | }, 177 | 178 | // opens the menu 179 | openMenu: function() { 180 | if (this.element.hasClass('showMenu')) { 181 | return; 182 | } 183 | this.element.trigger('openMenu.dropdownMenu', this); 184 | this.element.addClass('showButton showMenu'); 185 | this.element.find('div:first').attr("aria-hidden", "false"); 186 | this.element.find('a:first').attr("aria-expanded", "true"); 187 | this.focus('+1'); 188 | }, 189 | 190 | // closes the menu 191 | closeMenu: function() { 192 | if (!this.element.hasClass("showMenu")) { 193 | return; 194 | } 195 | this.element.removeClass("showMenu"); 196 | this.element.find("div:first").attr("aria-hidden", "true"); 197 | this.element.find(".menuButton").attr("aria-expanded", "false"); 198 | this.element.find(".menuButton").focus(); 199 | } 200 | }); 201 | 202 | 203 | }()); -------------------------------------------------------------------------------- /grid/include/jquery-ui-1.8.22.core.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.8.22 - 2012-07-24 2 | * https://github.com/jquery/jquery-ui 3 | * Includes: jquery.ui.core.js 4 | * Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ 5 | (function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.22",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;eAccessible grid layout with dropdown buttons and linked rows. Implemented with progressive enhancement.
21 | 22 |From the article Interactive elements within a grid layout by Dennis Lembree, PayPal Engineering.
97 | 98 | 99 | 100 | 101 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /hamburger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |Heavily modified from this Codepen by Marcy Sutton.
198 |She must have hidden the plans in the escape pod. Send a detachment down to retrieve them, and see to it personally, Commander. There'll be no one to stop us this time! You're all clear, kid. Let's blow this thing and go home! I need your help, Luke. She needs your help. I'm getting too old for this sort of thing. Escape is not his plan. I must face him, alone.
26 | 27 |I find your lack of faith disturbing. No! Alderaan is peaceful. We have no weapons. You can't possibly…
44 | 45 |She must have hidden the plans in the escape pod. Send a detachment down to retrieve them, and see to it personally, Commander. There'll be no one to stop us this time! You're all clear, kid. Let's blow this thing and go home! I need your help, Luke. She needs your help. I'm getting too old for this sort of thing. Escape is not his plan. I must face him, alone.
26 | 27 |I find your lack of faith disturbing. No! Alderaan is peaceful. We have no weapons. You can't possibly…
44 | 45 |Example of an accessible modal with resizing and progressive enhancement.
49 | 50 | 51 | 52 |Improvements/differences from original version:
53 |Ipsum test lorem.
45 | 46 |Example of a semantic and accessible design pattern for toggling the masking of a password input form field.
27 | 28 | 37 | 38 |This is an example of an accessible tab panel widget with ARIA and progressive enhancement. It follows the tabs pattern in the WAI-ARIA Authoring Practices. The second example adds instructions and an experimental tooltip (to help with keyboard discoverability) and ability for panels to focus to ensure all content can be accessed via keyboard only (of my favorite music groups, test the Marilyn Manson tabpanel with keyboard). Note: it appears that Firefox is now natively providing focusable panels.
116 | 117 |Below is an example of an accessible data table containing form elements (two select dropdowns).
21 |Notes:
22 |caption
and TH
elements.aria-labelledby
attribute which points to the text in the row and column headers.evil sith machine man
108 | 109 |cute droid
115 | 116 |little green jedi master
122 | 123 |Lucas ipsum dolor sit amet c-3p0 darth gonk windu greedo boba wedge organa antilles. Organa moff windu jango darth hutt dagobah darth. Kit maul qui-gon amidala. Mandalorians boba ewok greedo solo mara. Kessel han yavin darth solo. Grievous lando fett luke. Kessel gamorrean moff sidious.
134 |Organa darth moff windu. Hutt tatooine yoda darth. Kessel yoda solo lando jabba mandalore wampa. Leia mon dantooine solo coruscant. Luuke biggs jawa han organa darth solo coruscant. Kenobi jabba grievous yoda jango leia k-3po.
139 |Maul dooku organa solo solo sebulba darth lars. Kit tusken raider binks anakin r2-d2 palpatine maul yoda. Bespin jade fisto secura. Jinn darth jango antilles aayla baba. Grievous lando fett luke. Palpatine hutt jar moff organa fisto naboo k-3po.
144 |ruler of the dark side of the force
155 | 156 |all-purpose utility robot
161 | 162 |jedi council member, swamp-lover
167 | 168 |From the article A sweet toggle switch by PayPal Engineering
93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /transition/animation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |