Accordion menus follow the basic [Menu](menu.html) syntax of `<ul>`, `<li>`, and `<a>`. To convert a basic menu into an accordion, add the attribute `data-accordion-menu`. You probably also want it to be vertical, so add the class `.vertical` as well.
-Use `<span>` for elements that should open a nested menu. Use `<a>` for links outside of the behaviors of the menu functionality.
+Any `<a>` will behave like a standard link. However, any `<a>` paired with a nested `<ul>` menu will then slide that sub-menu up and down when clicked on.
<div class="primary callout">
<p>You can use the built-in <code>.nested</code> class to add an indent to a nested menu.</p>
</div>
```html
-<ul class="vertical tree" data-accordion-menu>
- <li><span>Item 1</span>
- <ul class="tree vertical nested">
- <li><span>Item 1A</span>
- <ul class="tree vertical nested">
- <li><span>Item 1Ai</span></li>
- <li><a href="http://www.google.com">External link</a></li>
- <li><span>Item 1Aiii</span></li>
- </ul>
- </li>
- <li><span>Item 1B</span></li>
- <li><span>Item 1C</span></li>
- </ul>
- </li>
- <li><span>Item 2</span>
- <ul class="tree vertical nested">
- <li><span>Item 2A</a></li>
- <li><span>Item 2B</a></li>
- </ul>
- </li>
- <li><a href="http://www.google.com">External link</a></li>
- </ul>
+<ul class="vertical menu" data-accordion-menu>
+ <li>
+ <a href="#">Item 1</a>
+ <ul class="menu vertical nested">
+ <li><a href="#">Item 1A</a></li>
+ <li><a href="#">Item 1B</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Item 2</a></li>
+</ul>
```
-<ul class="vertical tree" data-accordion-menu>
- <li><span>Item 1</span>
- <ul class="tree vertical nested">
- <li><span>Item 1A</span>
- <ul class="tree vertical nested">
- <li><span>Item 1Ai</span></li>
- <li><a href="http://www.google.com">External link</a></li>
- <li><span>Item 1Aiii</span></li>
- </ul>
- </li>
- <li><span>Item 1B</span></li>
- <li><span>Item 1C</span></li>
- </ul>
- </li>
- <li><span>Item 2</span>
- <ul class="tree vertical nested">
- <li><span>Item 2A</a></li>
- <li><span>Item 2B</a></li>
+<ul class="vertical menu" data-accordion-menu>
+ <li>
+ <a href="#">Item 1</a>
+ <ul class="menu vertical nested">
+ <li>
+ <a href="#">Item 1A</a>
+ <ul class="menu vertical nested">
+ <li><a href="#">Item 1Ai</a></li>
+ <li><a href="#">Item 1Aii</a></li>
+ <li><a href="#">Item 1Aiii</a></li>
</ul>
</li>
- <li><a href="http://www.google.com">External link</a></li>
- </ul>
-
-
----
-
-## Accessibility
-
-Accordion Menus by default are accessible through the use of various ARIA attributes. It is important not to use `<a>` unless you intend to have the menu item link off page or anchor accordingly.
+ <li><a href="#">Item 1B</a></li>
+ <li><a href="#">Item 1C</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">Item 2</a>
+ <ul class="menu vertical nested">
+ <li><a href="#">Item 2A</a></li>
+ <li><a href="#">Item 2B</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Item 3</a></li>
+</ul>
<li><a href="http://foundation.zurb.com/learn/responsive-reading.html">Responsive Reading</a></li>
</ul>
</li>
+
<li>
<a href="http://foundation.zurb.com/get-involved/support.html">Get Involved</a>
<ul class="submenu menu vertical" data-submenu>
<li><a href="#">Sites</a></li>
</ul>
</div>
+
+<div class="off-canvas position-top" id="offCanvasTop" data-off-canvas data-position="top">
+ <button class="close-button" aria-label="Close menu" type="button" data-close>
+ <span aria-hidden="true">×</span>
+ </button>
+ <ul class="mobile-ofc vertical menu">
+ <li><a href="#">Off-canvas</a></li>
+ <li><a href="#">Example</a></li>
+ <li><a href="#">Vertical</a></li>
+ <li><a href="#">Menu</a></li>
+ <li><a href="#">From</a></li>
+ <li><a href="#">The</a></li>
+ <li><a href="#">Top</a></li>
+ </ul>
+</div>
* @requires foundation.util.motion
* @requires foundation.util.nest
*/
+
class AccordionMenu {
/**
* Creates a new instance of an accordion menu.
});
}
+
+
/**
* Initializes the accordion menu by hiding all nested menus.
* @private
_init() {
this.$element.find('[data-submenu]').not('.is-active').slideUp(0);//.find('a').css('padding-left', '1rem');
this.$element.attr({
- 'role': 'tree',
+ 'role': 'menu',
'aria-multiselectable': this.options.multiOpen
});
$elem.attr({
'aria-controls': subId,
'aria-expanded': isActive,
- 'role': 'treeitem',
+ 'role': 'menuitem',
'id': linkId
});
$sub.attr({
'aria-labelledby': linkId,
'aria-hidden': !isActive,
- 'role': 'group',
+ 'role': 'menu',
'id': subId
});
});
_events() {
var _this = this;
- this.$element.find('li').each(function(idx) {
- if(idx > 0 ){
- $(this).attr('tabindex','-1');
- }
+ this.$element.find('li').each(function() {
var $submenu = $(this).children('[data-submenu]');
if ($submenu.length) {
- $(this).children('span').off('click.zf.accordionMenu').on('click.zf.accordionMenu', function(e) {
+ $(this).children('a').off('click.zf.accordionMenu').on('click.zf.accordionMenu', function(e) {
e.preventDefault();
- _this.setIndex(e.target);
+
_this.toggle($submenu);
});
}
$prevElement,
$nextElement,
$target = $element.children('[data-submenu]');
- _this.setIndex(e.target);
$elements.each(function(i) {
if ($(this).is($element)) {
- $prevElement = $elements.eq(Math.max(0, i-1)).first();
- $nextElement = $elements.eq(Math.min(i+1, $elements.length-1)).first();
+ $prevElement = $elements.eq(Math.max(0, i-1)).find('a').first();
+ $nextElement = $elements.eq(Math.min(i+1, $elements.length-1)).find('a').first();
if ($(this).children('[data-submenu]:visible').length) { // has open sub menu
- $nextElement = $element.find('li:first-child').first();
+ $nextElement = $element.find('li:first-child').find('a').first();
}
if ($(this).is(':first-child')) { // is first element of sub menu
- $prevElement = $element.parents('li').first();
- } else if ($prevElement.children('[data-submenu]:visible').length) { // if previous element has open sub menu
- $prevElement = $prevElement.find('li:last-child');
+ $prevElement = $element.parents('li').first().find('a').first();
+ } else if ($prevElement.parents('li').first().children('[data-submenu]:visible').length) { // if previous element has open sub menu
+ $prevElement = $prevElement.parents('li').find('li:last-child').find('a').first();
}
if ($(this).is(':last-child')) { // is last element of sub menu
- $nextElement = $element.parents('li').first().next('li').first();
+ $nextElement = $element.parents('li').first().next('li').find('a').first();
}
return;
}
});
+
Foundation.Keyboard.handleKey(e, 'AccordionMenu', {
open: function() {
if ($target.is(':hidden')) {
_this.down($target);
- //$target.find('li').first().first().focus();
+ $target.find('li').first().find('a').first().focus();
}
},
close: function() {
if ($target.length && !$target.is(':hidden')) { // close active sub of this item
_this.up($target);
} else if ($element.parent('[data-submenu]').length) { // close currently open sub
- $element.parents('li').first().first().focus();
+ _this.up($element.parent('[data-submenu]'));
+ $element.parents('li').first().find('a').first().focus();
}
},
up: function() {
- if( $prevElement.attr('tabindex') ){
- $prevElement.focus();
- } else {
- $prevElement.attr('tabindex', -1).focus();
- }
+ $prevElement.focus();
return true;
},
down: function() {
- $nextElement.attr('tabindex', -1).focus();
+ $nextElement.focus();
return true;
},
toggle: function() {
if ($element.children('[data-submenu]').length) {
_this.toggle($element.children('[data-submenu]'));
- } else {
- if( $element.find('a:first').attr('href') ){
- window.location = $element.find('a:first').attr('href');
- }
}
},
closeAll: function() {
e.stopImmediatePropagation();
}
});
- });
+ });//.attr('tabindex', 0);
}
/**
*/
hideAll() {
this.up(this.$element.find('[data-submenu]'));
- this.$element.find('li:first')[0].focus();
}
/**
this.down(this.$element.find('[data-submenu]'));
}
- /**
- * Sets the tabindex of the selected item to 0 and resets all the rest
- * @function
- */
- setIndex(el){
- this.$element.find('li').attr('tabindex','-1');
- if( $(el).is('li') ){
- $(el).attr('tabindex',0);
- } else {
- $(el).parent('li').attr('tabindex',0);
- }
- }
-
/**
* Toggles the open/close state of a submenu.
* @function
const Nest = {
Feather(menu, type = 'zf') {
+ menu.attr('role', 'menubar');
- if( type !== 'accordion'){
- menu.attr('role', 'menubar');
- menu.find('a:first').attr('tabindex', 0);
- } else {
- menu.find('li:first').attr('tabindex', 0);
- }
-
- var roleType = (type === 'accordion') ? 'treeitem' : 'menuitem',
- elementType = (type === 'accordion') ? 'span' : 'a',
- items = menu.find('li').attr({'role': roleType}),
+ var items = menu.find('li').attr({'role': 'menuitem'}),
subMenuClass = `is-${type}-submenu`,
subItemClass = `${subMenuClass}-item`,
- hasSubClass = `is-${type}-submenu-parent`,
- noSubClass = `is-${type}-submenu-none`;
+ hasSubClass = `is-${type}-submenu-parent`;
+
+ menu.find('a:first').attr('tabindex', 0);
items.each(function() {
var $item = $(this),
.attr({
'aria-haspopup': true,
'aria-expanded': false,
- 'aria-label': $item.children(elementType + ':first').text()
+ 'aria-label': $item.children('a:first').text()
});
$sub
'aria-hidden': true,
'role': 'menu'
});
- } else {
- $item.addClass(noSubClass).find('a').attr('tabindex',-1);
- var text = $item.addClass(noSubClass).find('a').text();
- if( $item.find('a').length > 0 ){
- $item.attr('aria-label',text + ' link');
- }
}
if ($item.parent('[data-submenu]').length) {
$accordionmenu-arrow-color: $primary-color !default;
@mixin foundation-accordion-menu {
- .tree {
- .is-accordion-submenu-none > a {
- padding: 0;
- line-height: $list-lineheight;
- }
-
- }
-
@if $accordionmenu-arrows {
- .is-accordion-submenu-parent > span {
+ .is-accordion-submenu-parent > a {
position: relative;
- display: block;
- color: $anchor-color;
- cursor: pointer;
-
- &:hover {
- color: $anchor-color-hover;
- }
&::after {
@include css-triangle(6px, $accordionmenu-arrow-color, down);
right: 1rem;
#{$global-right}: -4px;
}
-
}
- .is-accordion-submenu-parent[aria-expanded='true'] > span::after {
+ .is-accordion-submenu-parent[aria-expanded='true'] > a::after {
+ transform-origin: 50% 50%;
transform: scaleY(-1);
transform-origin: 50% 50%;
}
-
}
}
line-height: 1;
}
-
// Reset styles of inner elements
input,
select,
}
@mixin foundation-menu {
- .menu, .tree {
+ .menu {
@include menu-base;
@include menu-icons;
$gutters: $grid-column-gutter
) {
// Base properties
- flex: flex-grid-column($columns);
+ @include flex-grid-size($columns);
// Gutters
@include grid-column-gutter($gutters: $gutters);
describe('Accordion Menu', function() {
var plugin;
var $html;
- var template = `<ul class="vertical tree" data-accordion-menu>
- <li><span>Item 1</span>
- <ul class="tree vertical nested">
- <li><span>Item 1A</span>
- <ul class="tree vertical nested">
- <li><span>Item 1Ai</span></li>
- <li><a href="http://www.google.com">External link</a></li>
- <li><span>Item 1Aiii</span></li>
- </ul>
- </li>
- <li><span>Item 1B</span></li>
- <li><span>Item 1C</span></li>
- </ul>
+ var template = `
+ <ul class="vertical menu">
+ <li>
+ <a href="#">Item 1</a>
+ <ul class="menu vertical nested">
+ <li>
+ <a href="#">Item 1A</a>
+ <ul class="menu vertical nested">
+ <li><a href="#">Item 1Ai</a></li>
+ <li><a href="#">Item 1Aii</a></li>
+ <li><a href="#">Item 1Aiii</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Item 1B</a></li>
+ <li><a href="#">Item 1C</a></li>
+ </ul>
</li>
- <li><span>Item 2</span>
- <ul class="tree vertical nested">
- <li><span>Item 2A</a></li>
- <li><span>Item 2B</a></li>
+ <li>
+ <a href="#">Item 2</a>
+ <ul class="menu vertical nested">
+ <li><a href="#">Item 2A</a></li>
+ <li><a href="#">Item 2B</a></li>
</ul>
</li>
- <li><a href="http://www.google.com">External link</a></li>
- </ul>`;
+ <li><a href="#">Item 3</a></li>
+ </ul>`;
Foundation.AccordionMenu.defaults.slideSpeed = 0;
afterEach(function() {
<h1>Accordion Menu: Keyboard Control</h1>
<ul>
- <li>Hitting the tab key focuses you to the menu or the last open item.
- <li>The up and down arrow keys should navigate you through the menu items.</li>
- <li>The space bar, enter key and right arrow opens a menu if already closed. </li>
- <li>The space bar, enter key, esc and left arrow opens a menu if already open. </li>
+ <li>The Tab and down arrow keys should navigate down the menu, including open sub-menus.</li>
<li>Shift-tab and up arrow keys should navigate up the menu, including open sub-menus.</li>
- <li>When focused on a link item, the space bar and enter key should navigate to the link.</li>
+ <li>When focused on a parent menu, the space bar and Enter key should open or close the menu.</li>
+ <li>When focused on a link item, the space bar and Center key should navigate to the link.</li>
</ul>
- <ul class="vertical tree" data-accordion-menu>
- <li><span>Item 1</span>
- <ul class="tree vertical nested">
- <li><span>Item 1A</span>
- <ul class="tree vertical nested">
- <li><span>Item 1Ai</span></li>
- <li><a href="http://www.google.com">External link</a></li>
- <li><span>Item 1Aiii</span></li>
- </ul>
- </li>
- <li><span>Item 1B</span></li>
- <li><span>Item 1C</span></li>
- </ul>
- </li>
- <li><span>Item 2</span>
- <ul class="tree vertical nested">
- <li><span>Item 2A</a></li>
- <li><span>Item 2B</a></li>
- </ul>
- </li>
- <li><a href="http://www.google.com">External link</a></li>
+ <ul class="vertical menu" data-accordion-menu>
+ <li>
+ <a href="#">Item 1</a>
+ <ul class="menu vertical nested">
+ <li><a href="google.com">External link</a></li>
+ <li><a href="#">Item 1B</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Item 2</a></li>
</ul>
+ </div>
<script src="../assets/js/vendor.js"></script>
<script src="../assets/js/foundation.js"></script>