Another hamburger menu, as a web component. This extends @susbtrate-system/web-component.
Note
In the example page, you must be in mobile view to see the component.
See @substrate-system/hamburger for something similar but with different style.
npm i -S @substrate-system/hamburger-twoJust import; the library code calls window.customElements.define.
hamburger-two.
Note
This module only has client-side code. There is no provision for server-side rendering, because this element is only useful on the client-side.
Application code should listen for hamburger events, and show/hide the menu.
Pass the menu's id as the controls attribute.
<hamburger-two controls="mobile-nav"></hamburger-two>
<div id="mobile-nav" class="mobile-nav-menu">
<ul>
<li><a href="/hello">hello</a></li>
<li><a href="/abc">abc</a></li>
<li><a href="/def">def</a></li>
</ul>
</div>import { HamburgerTwo } from '@substrate-system/hamburger-two'
import '@substrate-system/hamburger-two/css'
// tag name is exposed as .TAG
const el = document.querySelector(HamburgerTwo.TAG)
// programmatically open the menu
el?.isOpen = true
// listen for events, then change the class on our navigation element
el?.addEventListener(HamburgerTwo.event('open'), () => {
debug('menu is open...')
document.querySelector('.mobile-nav-menu')!.classList.add('open')
})
// or use .on, because this extends @substrate-system/web-component
el.on('open', ev => {
// ...
})
el?.addEventListener(HamburgerTwo.event('close'), () => {
debug('menu is closed...')
document.querySelector('.mobile-nav-menu')!.classList.remove('open')
})Only display on small screens. This needs to be part of the application code; it is not in this library.
hamburger-two {
display: none;
}
/* show/hide our menu */
.mobile-nav-menu {
display: none;
&.open {
display: flex;
}
}
@media (width < 680px) {
hamburger-two {
display: block;
}
}controls-- theidof the menu element. It becomesaria-controlson the button, and the element moves focus into that menu on open.label-- the accessible name of the button. Default is"Menu".open-- present when the menu is open. Add or remove it to open or close the menu; this emits the matching event.
The element renders a single <button> with aria-label,
aria-expanded, and aria-controls.
- Clicking the button emits
openfirst, so the app can show the menu, then moves focus to the first focusable element in thecontrolsmenu. Opening by settingisOpenor theopenattribute does not move focus. - Pressing Escape while open closes the menu and returns focus to the button.
- Moving focus from the menu to an element outside of the menu and the hamburger closes the menu.
Typically you would use the tag in the DOM, then listen for events and show/hide a menu element in response.
HamburgerTwo.event('open')
// => 'hamburger-two:open'document.querySelector('hamburger-two')
.addEventListener(HamburgerTwo.event('open'), () => {
document
.querySelector('.mobile-nav-menu')
.classList
.add('open')
})HamburgerTwo.event('close')
// => 'hamburger-two:close'document.querySelector('hamburger-two')
.addEventListener(HamburgerTwo.event('close'), () => {
document
.querySelector('.mobile-nav-menu')
.classList
.remove('open')
})See ./example.
// after registering the component
document.body.innerHTML += `
<hamburger-two></hamburger-two>
`
const el = document.querySelector('hamburger-two')
el?.addEventListener(HamburgerTwo.event('open'), () => {
debug('menu is open...')
document.querySelector('.mobile-nav-menu')!.classList.add('open')
})
el?.addEventListener(HamburgerTwo.event('close'), () => {
debug('menu is closed...')
document.querySelector('.mobile-nav-menu')!.classList.remove('open')
})This exposes ESM and common JS via
package.json exports field.
import { HamburgerTwo } from '@substrate-system/hamburger-two'require('@substrate-system/hamburger-two')This package exposes minified JS and CSS files too. Copy them to a location that is accessible to your web server, then link to them in HTML.
cp ./node_modules/@substrate-system/hamburger-two/dist/index.min.js ./public/hamburger-two.min.js
cp ./node_modules/@substrate-system/hamburger-two/dist/style.min.css ./public/hamburger-two.css<head>
<link rel="stylesheet" href="./hamburger-two.css">
</head>
<body>
<!-- ... -->
<script type="module" src="./hamburger-two.min.js"></script>
</body>import '@substrate-system/hamburger-two/css'Or minified:
import '@substrate-system/hamburger-two/css/min'The element uses the shared --substrate-* variables, each with a
fallback:
--substrate-text-- the color of the lines. Defaultblackwhen closed andwhitewhen open.--substrate-focus-- the focus ring color. DefaultHighlight.--substrate-focus-width-- the focus ring width. Default2px.--substrate-radius-- the corner radius of the button, which shapes the focus ring. Default0.
Two more variables override --substrate-text for this element only.
--hamburger-color sets the color of the lines when closed, and
--burger-open-color sets the color of the close "x" when open.
:root {
--substrate-text: #222;
--substrate-focus: #0055d4;
--burger-open-color: white;
}The line animation is off when the user prefers reduced motion.
Run some tests locally with tape-run.
npm testStart a localhost server of the example page.
npm start- @substrate-system/hamburger The same thing, different style.