Skip to content

Conversation

@rshigg
Copy link
Contributor

@rshigg rshigg commented Jan 31, 2026

Summary

Refactors the package page sidebar to use collapsible sections with a <details>/<summary> pattern.

Changes

  • All sidebar sections are now collapsible
  • New package info components have been created which are essentially the existing components minus their title
  • Dependencies split into 3 separate collapsible sections (deps, peer, optional)
  • Sidebar moved before README in DOM order to make tabbing order more logical

@vercel
Copy link

vercel bot commented Jan 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Feb 1, 2026 0:21am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 1, 2026 0:21am
npmx-lunaria Ignored Ignored Feb 1, 2026 0:21am

Request Review

@danielroe
Copy link
Member

@rshigg this needs to work on hard reload, as well as remember the state of the sections, or we'll have layout shift when loading.

ideally if the collapsed/expanded state of each section can be controlled via css, rather than the implicit behaviour of <details> or JS, that would be best 🙏

class="group text-xs text-fg-subtle uppercase tracking-wider flex items-center gap-2"
<section
:id="id"
:aria-labelledby="id + '-title'"
Copy link
Contributor

@knowler knowler Jan 31, 2026

Choose a reason for hiding this comment

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

Suggested change
:aria-labelledby="id + '-title'"

You shouldn’t make this a region landmark. Named sections, which become region landmarks, should be used sparingly and not as a default for any component. See #384 for more detailed reasoning.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great callout I'll remove the label

Comment on lines 21 to 22
<details open class="col-span-full row-start-1 open:pb-2">
<summary
Copy link
Contributor

@knowler knowler Jan 31, 2026

Choose a reason for hiding this comment

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

I’m a bit wary of using <details>/<summary> elements for sections of a page. Namely because nesting a heading within a <summary> element is awkward for screen readers. My rule of thumb is that if you need a heading, don’t use <details>/<summary> and instead make your own collapsible sections.

For example, when traversing a page, if a (macOS) VoiceOver user encounters one of these, it won’t immediately surface the heading (and it won’t be clear there is one). Conversely, if the user is navigating by heading (which is very common for SR users), it won’t surface the fact that it’s within a <summary> element and so it won’t be clear that the corresponding content is collapsed. NVDA + Firefox and iOS VoiceOver do a bit better in this regard, but NVDA and JAWS have the same issues when paired with Edge.

A better structure is to nest the expanding/collapsing <button> within the heading:

<section>
  <h2><button type=button aria-expanded=true aria-controls=content-0>Expanded section</button></h2>
  <div id=content-0>
    <p>Collapsible content…</p>
  </div>
</section>
<section>
  <h2><button type=button aria-expanded=false aria-controls=content-1>Collapsed section</button></h2>
  <div id=content-1 hidden=until-found>
    <p>Collapsible content…</p>
  </div>
</section>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think getting rid of details/summary because of the headings might be throwing out the baby with the bath water.

Since all of these sections are in an aside we could simply get rid of the headings entirely. I like having the semantics of a disclosure widget for data that is considered "extra" to the main content.

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the headings are valuable for screen reader navigation, otherwise, you force screen reader users to find these sections themselves, so I wouldn’t remove them. And even within an <aside> element heading structure is still valuable.

Since the ancestor <aside> element is a descendant of an <article> element (a sectioning content element) it actually has no semantic value ARIA-wise (i.e. if it was labelled it would gain the role=complementary implicit ARIA semantics, see “3.5.10 aside (scoped to a sectioning content element)” in HTML-AAM. Firefox does something funky and might incorrectly surface it as role=complementary). Personally, I don’t think that the contents are tangential to the main content of the page though, so I wouldn’t label it (and I wouldn’t have even used an <aside> element in the first place—it’s doing no harm though).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gotcha, that all makes sense to me. Do you see value in the <article> ancestor here? we might want to remove all of these superfluous landmarks and just have everything inside a <main>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On second thought it might be beneficial to wrap the README in an <article>

represents a self-contained composition in a document, page, application, or site, which is intended to be independently distributable or reusable

Seems relevant since a README is a distributable standalone file

Copy link
Contributor

Choose a reason for hiding this comment

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

Good question. We don’t need to have the <article> for the page contents, but it doesn’t hurt. I think an <article> element could actually be better used to wrap the README, since that’s a standalone document (in which case, I would swap the <section> that currently wraps it with an <article>).

If the top-level <article> were removed it would cause the <aside> to gain the implicit complementary role (since <main> isn’t considered sectioning content), so in that case, I would actually change the <aside> to something else (a <div> element is fine IMO, since the sidebar here is more a presentational detail than a semantic one).

All of this is outside of the scope of the change this PR makes, so perhaps should be addressed separately. I might start a PR to wrap the README with an <article> instead of <section>.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great minds think alike! Yeah lets put the landmark changes in a separate PR

@rshigg
Copy link
Contributor Author

rshigg commented Jan 31, 2026

@rshigg this needs to work on hard reload, as well as remember the state of the sections, or we'll have layout shift when loading.

ideally if the collapsed/expanded state of each section can be controlled via css, rather than the implicit behaviour of <details> or JS, that would be best 🙏

We can set the open property on details to true programmatically with js in the prehydrate hook. Does that work for the usecase you imagine?

Regardless of how we achieve it my plan was to persist the open/closed states in local storage.

@danielroe
Copy link
Member

ideally the code runs before the dom is rendered (ie a script in head) so that the user never sees even a flash of the wrong state...

@rshigg
Copy link
Contributor Author

rshigg commented Jan 31, 2026

@danielroe I will revamp the markup based on @knowler's feedback and make sure to add toggling persistence without a flicker

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants