Skip to content

Refactor mobile menu to use Popover API - #4121

Merged
delucis merged 22 commits into
mainfrom
chris/sidebar-refactor
Sep 2, 2026
Merged

delucis merged 22 commits into
mainfrom
chris/sidebar-refactor

Conversation

@delucis

@delucis delucis commented Aug 13, 2026

Copy link
Copy Markdown
Member

Description

This PR refactors Starlight’s mobile menu toggle to use the Popover API instead of the current JS-powered <button> with aria-expanded pattern.

  • A small amount of JS remains but it’s now only a progressive enhancement for focus trapping. The core functionality of opening/closing the mobile menu and locking body scroll works even if JS breaks for whatever reason.

  • The JS is now in the PageFrame component as a custom element that attaches to the popover body instead of the menu button. It reacts to global events (matchMedia()) and the popover’s "toggle" event so it makes more sense to live alongside the element it attaches to. This also means the menu button component is now easier to override as any button with the correct popovertarget attribute will work.

  • CSS switches from hooking into [aria-expanded] to using the :popover-open pseudo class.

  • We no longer add a data-mobile-menu-expanded attribute to <body> when the menu is open and use body:has(#starlight__sidebar:popover-open) in CSS instead, which works without the JS-managed attribute.

  • While I was updating the button, I switched from aria-label to a visually hidden span of text, which is generally the recommended pattern for labels where possible.

Browser compatibility

Use of the Popover API requires slightly bumping our minimum supported browsers:

  • Firefox 121 (December 2023) => 125 (April 2024)
  • Chromium 111 (March 2023) => 116 (August 2023)
  • Safari 16.4 (March 2023) => 17.0 (September 2023) (for both macOS and iOS)

According to browsersl.ist, comparing before and after shows a drop in global coverage of 1 percentage point. The newest minimum supported browser will be Firefox 125, released 29 months ago.

N.B. that umbrella compatibility measures such as wf-popover show support only arriving later in some browsers. However, IIUC this is due to subfeatures that we are not relying on not being ready yet and the features we require are safe even in these older browser versions:

Safari on iOS had a long-standing bug in versions 17.0–18.2 which prevented tap-away clicks closing popovers as is expected. However, we do not require that behaviour in Starlight mobile menus as there is nowhere a user expects to click away to and the main control is the button.

Accessibility

The button with popovertarget and popover combo has built-in accessible roles equivalent to our previous aria-expanded pattern. I tested with VoiceOver in Firefox, Chrome, and Safari on macOS 26.5.1 and found the behaviour to be a very slight improvement in my opinion compared to the current announcements although both are basically equivalent. Would be great to test in more scenarios!

Demo

Here’s a small screen capture of the live Starlight docs and compared to this branch, showing the menu working without JavaScript after these changes:

popover.mp4

@changeset-bot

changeset-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c3a8f08

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@astrojs/starlight Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlify Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deploy Preview for astro-starlight ready!

Name Link
🔨 Latest commit c3a8f08
🔍 Latest deploy log https://app.netlify.com/projects/astro-starlight/deploys/6a97f1da501e0c0008bdec88
😎 Deploy Preview https://deploy-preview-4121--astro-starlight.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 100 (no change from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added the 🌟 core Changes to Starlight’s main package label Aug 13, 2026
@astrobot-houston

astrobot-houston commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
/index.html 6.1 KB (+0.02% 🔺)
/guides/example/index.html 6.02 KB (-1.76% 🔽)
/_astro/*.js 25.44 KB (0%)
/_astro/*.css 14.72 KB (-0.1% 🔽)

`toggle` fires after the menu has shown/hidden, by using `beforetoggle` we can ensure the changes all happen together
@delucis delucis added the 🌟 minor Change that triggers a minor release label Aug 13, 2026
@delucis delucis added this to the v0.42 milestone Aug 13, 2026
louisescher
louisescher previously approved these changes Aug 13, 2026

@louisescher louisescher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Tested on Zen 1.21.14b (Firefox 153.0.3) and Chrome 151.0.7922.109, both on Windows.
Edit: Also tested on Zen and Safari on MacOS, both work.

@trueberryless

Copy link
Copy Markdown
Contributor

Works on Firefox Android as well 👍

@HiDeoo HiDeoo added the pr-preview Trigger a preview release for this PR using pkg.pr.new label Aug 14, 2026
@github-actions github-actions Bot removed the pr-preview Trigger a preview release for this PR using pkg.pr.new label Aug 14, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 14, 2026

Copy link
Copy Markdown
pnpm add https://pkg.pr.new/@astrojs/starlight@4121

commit: 39a8b15

@HiDeoo HiDeoo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing that we can finally switch, thanks for taking care of the update 🙌

Left a few comments, but other than that, everything looks great. I tested on:

  • macOS: Chrome - Firefox - Safari
  • iOS: Safari
  • Windows: Chrome - Edge - Firefox

I also played around with some screen readers and the same browsers:

  • macOS VoiceOver
  • iOS VoiceOver
  • Windows NVDA
  • Windows JAWS

This is pretty much always equivalent or better like you mentioned and I didn't spot regressions so far.


Totally unrelated to this PR and wouldn't belong here as this is not a new behavior but while testing on Windows (and also noticeable on macOS with scrollbar visibility set to "Always"), we can probably avoid the buttons shift when opening the menu:

shift.mp4

Comment thread .changeset/clean-flies-start.md Outdated
Comment thread .changeset/long-jokes-post.md Outdated
Comment thread .changeset/long-jokes-post.md Outdated
Comment thread packages/starlight/components/MobileMenuToggle.astro Outdated
Comment thread packages/starlight/components/MobileMenuToggle.astro Outdated
Comment thread packages/starlight/src/components/PageFrame.astro
Comment thread CONTRIBUTING.md Outdated
Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com>
Comment thread .changeset/clean-flies-start.md Outdated
Comment thread packages/starlight/__e2e__/basics.test.ts Outdated
delucis and others added 3 commits August 14, 2026 19:28
Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com>
Co-Authored-By: HiDeoo <494699+HiDeoo@users.noreply.github.com>
HiDeoo
HiDeoo previously approved these changes Aug 14, 2026

@HiDeoo HiDeoo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adding the data attribute changes to the second changeset makes perfect sense.

Thanks for all the updates, this now looks perfect to me and ready 🚀 🧹

@trueberryless trueberryless left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good to me here. Well done, Chris with the speedy implementation and Hideo with the extraordinary review 🥳

I experimented a bit with the changes in my Sidebar Swipe plugin, but quickly realized that it's not possible to use the popover API there because I need to place the sidebar behind the actual content in order for the Discord-like swipe gesture to work. And AFAIU the intend of pop‎over is... well... being on top of the content, which doesn't go hand in hand with my plugin.

I therefore added the PageFrame.astro as a new component override and "reverted" the changes from here 😥
If someone knows some ingenious way to make it work cleaner, let me know.

EDIT: Chris suggested a potential solution, which would change the behavior a little bit on Discord. 🫶

@delucis delucis added the ✅ approved Pull requests that have been approved and are ready to merge when next cutting a release label Aug 31, 2026
@delucis
delucis merged commit 2623ae6 into main Sep 2, 2026
18 checks passed
@delucis
delucis deleted the chris/sidebar-refactor branch September 2, 2026 09:57
@astrobot-houston astrobot-houston mentioned this pull request Sep 2, 2026
dadezzz pushed a commit to dadezzz/university_notes that referenced this pull request Sep 6, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@astrojs/starlight](https://starlight.astro.build) ([source](https://github.com/withastro/starlight/tree/HEAD/packages/starlight)) | [`0.41.11` → `0.42.0`](https://renovatebot.com/diffs/npm/@astrojs%2fstarlight/0.41.11/0.42.0) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@astrojs%2fstarlight/0.42.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@astrojs%2fstarlight/0.41.11/0.42.0?slim=true) |

---

### Release Notes

<details>
<summary>withastro/starlight (@&#8203;astrojs/starlight)</summary>

### [`v0.42.0`](https://github.com/withastro/starlight/blob/HEAD/packages/starlight/CHANGELOG.md#0420)

[Compare Source](https://github.com/withastro/starlight/compare/@astrojs/starlight@0.41.11...@astrojs/starlight@0.42.0)

##### Minor Changes

- [#&#8203;3572](withastro/starlight#3572) [`292fb17`](withastro/starlight@292fb17) Thanks [@&#8203;HiDeoo](https://github.com/HiDeoo)! - Distributes package as JavaScript files with dedicated type declaration files instead of TypeScript source files.

- [#&#8203;4121](withastro/starlight#4121) [`2623ae6`](withastro/starlight@2623ae6) Thanks [@&#8203;delucis](https://github.com/delucis)! - Simplifies markup for Starlight’s mobile menu toggle

  **⚠️ Potentially breaking change:** If you use a theme plugin, custom styles, or component overrides targeting the `MobileMenuToggle` button or `PageFrame` components, you may need to adjust these for the new markup. The button is no longer wrapped in a `<starlight-menu-button>` custom element and no longer uses the `aria-expanded` attribute. Instead, you can use the `.sl-menu-button` class name to target the button and the `:popover-open` pseudo-class to style the menu open state specifically.

  In the following example, custom styles for the menu button are updated for the new approach:

  ```diff
  - starlight-menu-button button {
  + .sl-menu-button {
    color: var(--sl-color-text);
  }

  - starlight-menu-button[aria-expanded='true'] button {
  + .sl-menu-button:has(~ :popover-open) {
    color: var(--sl-color-text-accent-high);
  }
  ```

  See [`MobileMenuToggle.astro`](https://github.com/withastro/starlight/blob/main/packages/starlight/components/MobileMenuToggle.astro) and [`PageFrame.astro`](https://github.com/withastro/starlight/blob/main/packages/starlight/components/PageFrame.astro) on GitHub for the full source code of the updated components.

- [#&#8203;3572](withastro/starlight#3572) [`292fb17`](withastro/starlight@292fb17) Thanks [@&#8203;HiDeoo](https://github.com/HiDeoo)! - Removes the `tagline` configuration option, which was never used.

  If your configuration included a `tagline` option, you can safely remove it without any replacement.

- [#&#8203;4134](withastro/starlight#4134) [`6135f01`](withastro/starlight@6135f01) Thanks [@&#8203;HiDeoo](https://github.com/HiDeoo)! - Updates internal `@astrojs/mdx`, `@astrojs/markdown-satteri`, and `satteri` dependencies.

  ⚠️ **BREAKING CHANGE:** The following minimum versions are now required:

  - `astro` v7.2.10 or later
  - `@astrojs/markdown-satteri` 0.4.0 or later (if you use it)
  - `@astrojs/markdown-remark` 7.3.0 or later (if you use it)

  Please update Starlight and Astro together:

  ```sh
  npx @astrojs/upgrade
  ```

- [#&#8203;4121](withastro/starlight#4121) [`2623ae6`](withastro/starlight@2623ae6) Thanks [@&#8203;delucis](https://github.com/delucis)! - Refactors Starlight’s mobile menu toggle to work when JavaScript fails or is disabled

  ⚠️ **BREAKING CHANGE:** This release drops official support for Chromium-based browsers prior to version 116 (released August 2023), Safari-based browsers prior to version 17.0 (released September 2023), and Firefox prior to version 125 (released April 2024). You can find a list of currently supported browsers and their versions using this [browserslist query](https://browsersl.ist/#q=%3E+0.5%25%2C+not+dead%2C+Chrome+%3E%3D+116%2C+Edge+%3E%3D+116%2C+Firefox+%3E%3D+125%2C+Safari+%3E%3D+17.0%2C+iOS+%3E%3D+17.0%2C+not+op_mini+all).

  This change also removes the `data-mobile-menu-expanded` attribute, which was previously added to `<body>` while the mobile menu is open. If you have custom code that was depending on this attribute, you will need to update it to use a new selector to check if the mobile menu is open.

  In the following example, a custom background colour for the site header while the menu is open is updated for the new approach:

  ```diff
  - [data-mobile-menu-expanded] header {
  + body:has(sl-sidebar-pane:popover-open) header {
    background-color: var(--sl-color-bg);
  }
  ```

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC42NS4yIiwidXBkYXRlZEluVmVyIjoiNDQuNjUuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->
erwinkramer added a commit to erwinkramer/erwinkramer.github.io that referenced this pull request Sep 12, 2026
Starlight 0.42 (PR withastro/starlight#4121) replaced the starlight-menu-button custom element and data-mobile-menu-expanded body attribute with a Popover API toggle (.sl-menu-button) and :popover-open state. Update theme selectors accordingly so the hamburger button and sidebar pane keep their dark/glass styling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✅ approved Pull requests that have been approved and are ready to merge when next cutting a release 🌟 core Changes to Starlight’s main package 🌟 minor Change that triggers a minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants