Skip to content

Fix rehype accessible table plugins - #2493

Open
ShubhamOulkar wants to merge 11 commits into
expressjs:mainfrom
ShubhamOulkar:fix-rehype-accessible-table-plugins
Open

Fix rehype accessible table plugins#2493
ShubhamOulkar wants to merge 11 commits into
expressjs:mainfrom
ShubhamOulkar:fix-rehype-accessible-table-plugins

Conversation

@ShubhamOulkar

@ShubhamOulkar ShubhamOulkar commented Aug 30, 2026

Copy link
Copy Markdown
Member

This plugin was failing because it only handled standard Hypertext Abstract Syntax Tree format table nodes and missed tables authored as raw HTML inside MDX/Markdown (mdxJsxFlowElement, mdxJsxTextElement).

The fix registers the plugin in both Markdown and MDX pipelines and updates the transform to support both raw HTML and standard table nodes, ensuring consistent scrollable table behavior.

This fixes the missing wrapper for raw HTML tables: https://deploy-preview-2493--expressjscom-preview.netlify.app/en/5x/guide/behind-proxies/

and markdown-generated tables: https://deploy-preview-2493--expressjscom-preview.netlify.app/en/resources/middleware/

closes #2484

@ShubhamOulkar
ShubhamOulkar requested a review from a team as a code owner August 30, 2026 06:35
@netlify

netlify Bot commented Aug 30, 2026

Copy link
Copy Markdown

Deploy Preview for expressjscom-preview ready!

Name Link
🔨 Latest commit 5a71467
🔍 Latest deploy log https://app.netlify.com/projects/expressjscom-preview/deploys/6a9a46d5d3b7f70009688c24
😎 Deploy Preview https://deploy-preview-2493--expressjscom-preview.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: 97 (no change from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 100 (no change from production)
PWA: 80 (no change from production)
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.

@krzysdz krzysdz 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.

Somehow this PR breaks multiple things (other plugins?).

The tables in "Moving to Express 4" don't have scope on <th> elements, because <tbody> is missing:

Image

If I'm reading the code (and old comments) correctly these should have scope="row" (according to code, not really how it should be). On a closer look scope seems to be missing everywhere (e.g. in the routing guide).

As a side note, I've noticed that the HTML <table>s have <p>s inside cells if the text is multiline. In the big tables ("behind proxies") this is may not be obvious, but in "Migrating to Express 4" only some rows have <p> elements and this causes them to have much bigger padding than other rows - rewriting them to Markdown (#2485) lets us avoid this and fixes the table structure (missing <thead>).

Comment thread astro.config.mjs Outdated
}),
accessibleTablesIntegration(),
mdx(),
mdx({ rehypePlugins: [rehypeAccessibleTables] }),

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.

Something in this PR breaks syntax highlighting and adding <a> to headers (all plugins?) and I think this may be the culprit.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch, and thanks for the note. I only checked that scroll bars were being added for both HTML and Markdown-generated tables, and I m +1 on rewriting the two tables in #2485 to Markdown (Markdown tables render as semantic HTML in MDX and will produce thead/tbody structures). That approach makes sense and I support including those Markdown table changes from #2485. Converting every raw-HTML table across the site isn’t economical to do immediately we will keep converting pages over time as we come across them.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Something in this PR breaks syntax highlighting and adding to headers (all plugins?) and I think this may be the culprit.

fixed in 6cde5c8


parent.children.splice(index, 1, wrapper);
// Skip the inserted wrapper so we don't revisit the table inside it
return [SKIP, index + 1];

@krzysdz krzysdz Aug 31, 2026

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.

Since now there is only a single visit() call, we must not skip visiting the children of inserted node (the <table> may be visited twice, but there is a parentAlreadyWrapped check) or the scope won't be added. However, there's a line in unist-util-visit readme that makes me think that using something else than SKIP when replacing a node may lead to problems:

Replacing node itself, if SKIP is not returned, still causes its descendants to be walked (which is a bug).

Maybe it would be safer to use a separate visit() call for adding the scope? I know that this comes with a performance hit (the website already takes a while to build), but it sounds like a better idea.

Even with this fixed, the tables in "Moving to Express 4" don't have the scope, because there is neither <thead> nor <tbody> in the source file - the <table> is directly followed by <tr>s:

<table class="doctable" border="1">
<tr>
<th>Express 3</th>
<th>Express 4</th>
</tr>
<tr>

Will you copy the rewritten tables from #2485 to this PR, or should I just remove the added lines with wrapper (from "behind proxies") and make #2485 just a rewrite of those 2 HTML tables to markdown?

@ShubhamOulkar ShubhamOulkar Sep 2, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Maybe it would be safer to use a separate visit() call for adding the scope? I know that this comes with a performance hit (the website already takes a while to build), but it sounds like a better idea.

I am aware of this and may be optimize will improve build time. https://docs.astro.build/en/guides/integrations-guide/mdx/#optimize

make #2485 just a rewrite of those 2 HTML tables to markdown?

yes, rewrite tables from behind proxies. Rewritten markdown tables in "Moving to Express 4" LGTM.

…es and wrap tables without affecting traversal
@ShubhamOulkar

Copy link
Copy Markdown
Member Author

4e49d37 Uses separate passes to keep AST traversal predictable while supporting both HAST and MDX JSX tables. Build time remains unchanged.

Comment on lines +150 to +154
/*
* Don't continue traversing into the table after moving it.
* Scope processing has already happened in the previous passes.
*/
return;

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.

Returning undefined will cause the visit() to check also the children nodes. SKIP should be returned if we don't want to traverse the children nodes.

I tested adding return SKIP here, in line 136, after line 116 and after line 93 - everything still works, no observable improvement in build time (the plugins probably don't affect it very much).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

SKIP should be returned if we don't want to traverse the children nodes.

It's bug you mentioned earlier.

krzysdz added a commit to krzysdz/expressjs.com that referenced this pull request Sep 2, 2026
@krzysdz

krzysdz commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

This wrapper from a table in 5.1 release post can also be removed.

<div markdown="1" style="overflow-x: auto; max-width: 100%;">

It doesn't do anything, because the table-scroller inside scrolls instead.

Firefox dev tools inspector: div with style "overflow-x: auto" that has a table-scroller dive inside. The table-scroller div is scrollable, because the table that it wraps overflows it. The outer div does nothing.

ShubhamOulkar and others added 2 commits September 3, 2026 05:35
Co-authored-by: krzysdz <12915102+krzysdz@users.noreply.github.com>


Co-authored-by: krzysdz <12915102+krzysdz@users.noreply.github.com>
@ShubhamOulkar
ShubhamOulkar requested a review from a team as a code owner September 3, 2026 05:37
@ShubhamOulkar
ShubhamOulkar requested review from krzysdz and removed request for a team September 3, 2026 05:37
@ShubhamOulkar

Copy link
Copy Markdown
Member Author

removed html wrapper in 07c9eca

image

@krzysdz

krzysdz commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

scroller (from <div class="table-scroller"> in the new docs) is not recognised by CSpell. This can be fixed by adding it to the project-words.txt.

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.

A page in the documentation seems messy in small screens

2 participants