Create a Mobile Menu with the Popover API and No JavaScript
The “checkbox hack” is a CSS trick that uses a hidden HTML checkbox and the :checked pseudo-class to toggle UI states without using JavaScript. Typically, it involves a checkbox paired with a <label> (linked via the for attribute) styled to look like a button. When clicked, the label toggles the checkbox, and CSS selectors targeting :checked show or hide content, like a mobile menu.
This method was previously used for the website’s mobile navigation. When the screen width dropped below a certain threshold, the expanded menu was replaced by a hamburger icon (the three horizontal lines). It worked, but the solution felt clunky. The code was messy, not great for accessibility (despite passing tests), and felt like… well, a hack.
The Popover API offered a better solution.
What Is the Popover API
Just to be clear, this is not the pastry. That popover is flaky and terrible at managing UI state, though it is delicious in fallback situations.
The Popover API is a modern HTML feature that enables developers to create lightweight overlays such as menus, tooltips, dialogs, or dropdowns without JavaScript for basic toggling. It allows content to appear on top of other content using only HTML and CSS. Think of it as a native way to create non-modal overlays such as menus, tooltips, and dropdowns without having to implement the underlying show/hide behavior.
Popover content is triggered using standard HTML attributes. No JavaScript is needed unless advanced behavior is required. Once the mechanics became clear, the checkbox hack on this website was replaced with clean, semantic HTML and CSS. JavaScript is not a problem, but native HTML/CSS is preferable where it can do the job.
The Popover API is often compared to the <dialog> element, and the two serve different purposes. A <dialog> opened with showModal() traps focus, blocks interaction with the rest of the page, and is suited to content that demands a response, like a confirmation prompt. A popover does not trap focus or block the page by default, which makes it a better fit for non-blocking UI like menus, tooltips, and dropdowns, where the rest of the page should remain usable.
HTML Attributes
The Popover API uses a few new HTML attributes. While these can technically be used on any HTML element, they are most commonly applied to containers like <nav> or <div>.
| Attribute | Purpose |
|---|---|
popover | Marks an element as a popover that can be toggled. |
popovertarget | Declares which element should be shown/hidden. |
popovertargetaction | Specifies the action: toggle, show, or hide. |
While this implementation relies entirely on HTML attributes, the Popover API also exposes three JavaScript methods for programmatic control: showPopover(), hidePopover(), and togglePopover(). These are useful when a popover needs to open or close in response to something other than a direct click, such as a form validation event or an analytics trigger. For a straightforward mobile menu, the declarative attributes are sufficient.
Browser Support
The Popover API is now supported by current versions of the major browsers, although older browser versions may not support it.
| Browser | Version Supported |
|---|---|
| Chrome | 114+ |
| Firefox | 125+ |
| Safari | 17+ |
| Edge (Chromium) | 114+ |
| Opera | 100+ |
There is no straightforward polyfill for the Popover API in older browsers. Sites that need to support older browsers should treat this as a progressive enhancement. In this implementation, browsers without Popover API support will not have a functional mobile menu because the mobile toggle depends on the API. If older browsers are part of the support requirements, provide a fallback implementation rather than relying on this version alone.
Mobile Menu Using the Popover API
Here is how to build a responsive mobile menu using only HTML and CSS.
HTML
The menu consists of two <nav> elements, one for desktop and one for mobile, and a pair of buttons to open and close the popover. This separation ensures that each menu is styled and behaves appropriately based on the viewport size.
Key Elements
- The desktop menu (
<nav id="desktop-menu">) is the traditional, always-visible navigation bar shown on larger screens. It includes links arranged horizontally. - The
Show Menubutton (<button id="mobile-menu-btn-show">) is hidden by default but becomes visible on smaller viewports (below768px). It includes:popovertarget="mobile-menu"which links the button to the popover element,popovertargetaction="show"which indicates this button opens the popover when pressed, and ARIA attributes (aria-label,aria-controls) to improve screen reader support. - The mobile menu (
<nav id="mobile-menu" popover>) which is hidden by default and appears as a popover when triggered. Thepopoverattribute designates it as an interactive overlay. Its structure mirrors the desktop menu, but is optimized for vertical display on mobile. - The
Close Menubutton (<button id="mobile-menu-btn-close">) which is placed inside the mobile menu and includes:popovertarget="mobile-menu"which targets the same popover element,popovertargetaction="hide"which indicates this button hides the popover when pressed, and ARIA attributes to assist with accessibility.
<header>
<a href="/">My Site</a>
<nav id="desktop-menu">
<a href="/">Home</a>
<a href="/about/">About</a>
<a href="/blog/">Blog</a>
</nav>
<button
id="mobile-menu-btn-show"
popovertarget="mobile-menu"
popovertargetaction="show"
aria-label="Show Site Menu"
aria-controls="mobile-menu"
>
Show Menu
</button>
<nav id="mobile-menu" popover>
<button
id="mobile-menu-btn-close"
popovertarget="mobile-menu"
popovertargetaction="hide"
aria-label="Close Site Menu"
aria-controls="mobile-menu"
>
Close Menu
</button>
<a href="/">Home</a>
<a href="/about/">About</a>
<a href="/blog/">Blog</a>
</nav>
</header>
The default auto popover state, which applies simply by adding the popover attribute, closes automatically on an outside click or when the Escape key is pressed. This light-dismiss behavior is built into the browser and requires no additional markup or code.
CSS
The CSS handles layout, visibility, and responsive behavior, allowing the mobile menu to work without JavaScript. Flexbox is used to arrange elements inside the header and menus, and media queries adjust the layout for smaller screens.
By default, the desktop menu is shown and the mobile menu (marked with the popover attribute) is hidden. When the viewport shrinks below 768px, the desktop menu is hidden, and the Show Menu button appears. Clicking this button reveals the mobile menu as a popover overlay.
The mobile menu is styled to appear from the top-right corner and extend the full height of the screen. It stacks links vertically and includes a Close Menu button that hides the popover when clicked. The :popover-open pseudo-class is used to apply styles when the popover is visible, and the ::backdrop pseudo-element adds a translucent dark layer behind the menu to visually separate the menu from the page content.
This setup provides responsive navigation with a native-feeling toggle experience.
header {
display: flex;
justify-content: space-between;
}
#desktop-menu {
display: flex;
gap: 1.5rem;
}
#mobile-menu-btn-show {
display: none;
cursor: pointer;
}
#mobile-menu-btn-close {
width: fit-content;
cursor: pointer;
}
#mobile-menu {
flex-direction: column;
gap: 1.5rem;
height: 100%;
inset: unset;
top: 0;
right: 0;
background-color: #fff;
border: none;
padding: 1rem 0.25rem 0 1.5rem;
}
#mobile-menu:popover-open {
display: flex;
}
#mobile-menu::backdrop {
background-color: rgba(0, 0, 0, 0.2);
}
#mobile-menu a {
width: fit-content;
}
@media (max-width: 768px) {
#desktop-menu {
display: none;
}
#mobile-menu-btn-show {
display: flex;
}
}
Results
The final implementation delivers a clean, responsive navigation menu that works smoothly across devices. On desktop screens, the standard horizontal menu is displayed. On smaller viewports (like phones or tablets), the desktop menu is hidden and a Show Menu button appears. Tapping the button opens the mobile menu as a popover from the top-right corner, complete with a semi-transparent backdrop.
Inside the popover, links are stacked vertically for easy tapping, and a Close Menu button hides the menu. Again, all interactions happen without JavaScript, using only HTML, CSS, and the built-in Popover API.
This result demonstrates a modern, JavaScript-free approach to mobile navigation using native web platform features.

Summary
Beyond menus, the Popover API pairs well with CSS anchor positioning for building tooltips and dropdowns that stay attached to a triggering element. Its scope reaches well past mobile navigation. The Popover API offers a clean way to build interactive elements like mobile menus without JavaScript or hacks required. It improves semantics, accessibility, and maintainability instead of relying on the checkbox hack.