Burger is a fullscreen menu in one stylesheet and one module
Burger - The minimal hamburger menu with fullscreen navigation.
At a glance
- What is it?
- The burger package ships a dependency free hamburger menu that derives its whole visual state from a single aria-expanded attribute, and its use of cascade layers means your own unlayered CSS wins without a single important flag.
- Who is it for?
- Burger suits a team that wants a fullscreen mobile navigation with real keyboard and screen reader behaviour, and it suits anyone who is tired of a hamburger menu implementation that fights their stylesheet, since the cascade layer arrangement means the package gets out of the way by default.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One attribute drives the entire visual state
Burger is described as a minimal hamburger menu with fullscreen navigation, and the mechanism is unusually clean. The toggle is a button element carrying aria-expanded and aria-controls, and the navigation is a nav element around a ul. The README states that aria-expanded is the only state there is, and that the stylesheet derives the overlay, the bars and the list animation from it. There is no open class to add and no is-active to remove, and no JavaScript class list juggling to get out of sync with the markup. The package publishes as the-burger on npm and the whole thing is one stylesheet and one ES module with no dependencies. The audience is a developer who wants a working menu rather than a component framework, and the design means the state lives in the accessibility tree rather than in a private attribute, which is why the animation and the assistive technology cannot disagree.
The markup contract is short and worth copying exactly
The quickstart shows the entire structure, a nav with a list of links, then a container holding the toggle button and a brand link. The three spans inside the button are the bun elements, and their modifier names are what the stylesheet animates into a cross.
<nav class="b-nav" id="b-nav" aria-label="Main">
<ul>
<li><a class="b-link b-link--active" href="#" aria-current="page">Home</a></li>
<li><a class="b-link" href="#">About</a></li>
<li><a class="b-link" href="#">Contact</a></li>
</ul>
</nav>
<div class="b-container">
<button class="b-menu" type="button" aria-expanded="false" aria-controls="b-nav" aria-label="Open menu">
<span class="b-bun b-bun--top"></span>
<span class="b-bun b-bun--mid"></span>
<span class="b-bun b-bun--bottom"></span>
</button>
<a href="#" class="b-brand">Burger</a>
</div>The class names are the API, and the ids have to match: the aria-controls on the button points at the nav id, and the script uses that relationship to know which element to expand. Note that the active link carries both a modifier class and aria-current, so the visual state and the announced state are set together rather than one being derived from the other.
Auto-wiring on import, or a manual init with a teardown
The script is an ES module, so type=module is required, and it wires up every .b-menu on load. That is the zero configuration path, and it is fine when you have one menu. If you want to wire a toggle yourself, the package exports an initBurger function that takes an element and returns a teardown.
import { initBurger } from "the-burger";
const teardown = initBurger(document.querySelector(".b-menu"));The teardown return value matters more than it first appears. The automatic path attaches listeners to every matching element at import time, which means a menu added to the page later, or one inside a component that mounts after the module loads, will not be wired. The manual init function exists for those cases, and returning a teardown means a component can clean up when it unmounts, which matters in a single page application where the same element may be mounted and unmounted repeatedly. The demo in the README is described as open and close the menu, then try it with the keyboard alone, and that is the right way to evaluate a component whose selling point is behaviour rather than appearance.
The accessibility work is the substance, not the animation
The list of what you get is worth reading closely because the accessibility items are the ones most hamburger implementations skip. Escape closes the menu and returns focus to the toggle, so keyboard users are not stranded. A closed menu stays out of the tab order, which means a screen reader user is not cycling through a menu they cannot see. While the menu is open the rest of the page goes inert, so Tab cycles inside the navigation. The page locks and the panel scrolls, so a long list stays reachable rather than the background scrolling behind it. The menu is viewport-anchored, behaving the same at the bottom of a long page as at the top. And forced colors and reduced motion are both honored, with 44px minimum touch targets. This is a coherent treatment of the problem, and it is the reason to choose this package over a dozen lines of your own JavaScript that happens to toggle a class.
Cascade layers are how the package avoids important
The theming section explains that every value is a --burger custom property and that you redeclare the ones you want.
:root {
--burger-accent: #111;
--burger-on-accent: #fff;
--burger-size: 48px;
--burger-font-family: "Inter", sans-serif;
--burger-duration: 0.25s;
}The important design decision is stated next: sizes derive from each other, so overriding --burger-size moves the bars, the cross and the navigation offset together, and every rule sits in a cascade layer. The README then explains what that means in practice, which is that layered CSS loses to unlayered CSS regardless of specificity, so anything in your own stylesheet wins without !important. That is the opposite of the usual component library experience, where a component's rules arrive with the weight of a selector and you end up fighting it with !important. Here the package is deliberately weaker, which is the correct default for a component you do not own.
Browser support is the hard boundary
The README states the support matrix plainly: Chrome and Edge 123 and newer, Firefox 128 and newer, and Safari and iOS Safari 17.5 and newer, and it gives the reason, which is that Burger uses cascade layers, the :has() selector and logical properties. That is a recent baseline, and it is the first thing to check. If your audience includes older browsers, or if an internal build pipeline still targets them, this package will not work as shipped, and the workarounds are not small because all three features are load bearing. The other practical limit is scope. The package is one specific menu, a fullscreen overlay with three bars that become a cross, and it is not a navigation system. It does not route, it does not manage a router, it does not nest, and it does not provide a drawer component with a different shape. The build tooling reflects the same minimalism. The package scripts use lightningcss to bundle and minify the CSS, esbuild to bundle the TypeScript, and the repository carries Playwright and Vitest configuration alongside oxlint and oxfmt for linting and formatting, so the project has real test coverage for a package this small.
Editorial conclusion
Burger suits a team that wants a fullscreen mobile navigation with real keyboard and screen reader behaviour, and it suits anyone who is tired of a hamburger menu implementation that fights their stylesheet, since the cascade layer arrangement means the package gets out of the way by default. It is the wrong choice for a project that must support browsers older than Chrome 123, Firefox 128 and Safari 17.5, and it is the wrong choice if you want a differently shaped menu, because the whole design is one specific visual form. Before adopting it, read the accessibility contract in the README, since the inert background and the focus return on Escape are the parts you would otherwise have to rebuild, and decide whether your content security policy allows the ES module and the cascade layers the stylesheet depends on. The last push was on 2026-10-19 and the current release is v3.0.1 from 2026-07-28.
Frequently asked questions
How do I install the Burger hamburger menu?
Install the package with npm install the-burger, or load both files from a CDN with no build step. The script is an ES module, so type="module" is required, and it wires up every .b-menu element on load.
How do I control the state of the Burger menu?
The toggle button carries aria-expanded and aria-controls, and the README states that aria-expanded is the only state there is, with the stylesheet deriving the overlay, the bars and the list animation from it.
What accessibility behaviour does Burger implement?
Escape closes the menu and returns focus to the toggle, a closed menu stays out of the tab order, the rest of the page goes inert while the menu is open so Tab cycles inside the navigation, the page locks while the panel scrolls, and forced colors and reduced motion are honored with 44px minimum touch targets.
Which browsers does Burger support?
Chrome and Edge 123 and newer, Firefox 128 and newer, and Safari and iOS Safari 17.5 and newer, because Burger uses cascade layers, the :has() selector and logical properties.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mblode-burger)Was this useful?