Skip to content

Ensure sr-only hides the caption of a table - #20528

Open
snmsoodan wants to merge 2 commits into
tailwindlabs:mainfrom
snmsoodan:fix-20510-sr-only-caption
Open

snmsoodan wants to merge 2 commits into
tailwindlabs:mainfrom
snmsoodan:fix-20510-sr-only-caption

Conversation

@snmsoodan

@snmsoodan snmsoodan commented Sep 28, 2026 •

Copy link
Copy Markdown

Fixes #20510

sr-only doesn't hide a <caption> when it is applied to a <table> in Firefox:

<table class="sr-only">
  <caption>Visible in Firefox</caption>
  <tbody>…</tbody>
</table>

Summary

sr-only hides an element by shrinking it to 1px and clipping it with clip-path: inset(50%), but neither of those hides a <caption> in Firefox:

  • A table can't shrink below the size of its own content, so width/height: 1px plus overflow: hidden clip nothing.
  • Firefox applies a <table>'s clip-path to the inner grid box of the table, while Chrome and Safari apply it to the outer table wrapper box (see css-tables-3 §3.6.1). A <caption> is rendered in the outer table wrapper box, so in Firefox it lives outside the region that clip-path clips and stays visible. This is the long-standing Mozilla bug 1998269.

Chrome and Safari are unaffected because the box they clip is the one the caption is in.

This change clips the caption itself as well, so sr-only hides it no matter which box an engine decides to clip:

.sr-only > caption {
  clip-path: inset(50%);
}

clip-path clips painting and hit-testing, and it doesn't remove the element from the accessibility tree, which matches how sr-only is meant to work. The child selector is deliberately not wrapped in :where(...) so that a preflight or user reset can't silently defeat it.

not-sr-only has to undo the same rule, so the caption becomes visible again for sr-only md:not-sr-only:

.not-sr-only > caption {
  clip-path: none;
}

Test plan

Two tests were added, both of which fail before this change:

  1. packages/tailwindcss/src/utilities.test.ts — the sr-only snapshot now includes .sr-only > caption { clip-path: inset(50%) }.
  2. packages/tailwindcss/tests/ui.spec.ts — a new test renders a table with a caption and asserts the caption's computed clip-path is inset(50%), and a second one checks that sr-only md:not-sr-only clips the caption below md and unclips both the table and its caption above it.

Commands run locally:

# before the change (negative control)
$ playwright test --project=chromium --project=webkit -g "sr-only"
  Expected: "inset(50%)"
  Received: "none"
  2 failed

# after the change
$ vitest run packages/tailwindcss/src
  Test Files  42 passed (42)
       Tests  5015 passed | 1 skipped (5016)

$ playwright test --project=chromium --project=webkit
  202 passed, 2 skipped

I also measured the mechanism directly in Chromium: before the change the caption's computed clip-path is none and the caption is still hit-testable (document.elementFromPoint() over it returns the caption), while the <table> itself reports inset(50%) and is no longer hit-testable. After the change the caption reports inset(50%) and is no longer hit-testable, so it is genuinely hidden and no longer intercepts clicks.

One caveat about the test plan: I was not able to run --project=firefox in my environment — the headless Firefox bundle Playwright downloads won't launch on this machine (sandbox_extension_issue_file_to_process failed for …/plugin-container.app: 1 (Operation not permitted), and browserType.launch then times out), and no system Firefox is installed. So Firefox itself is the one engine I did not observe; the behaviour above comes from the issue report and the spec. The new test asserts the cascade rule rather than an engine-specific box layout, which is why I'd expect it to hold in Firefox too — it should be confirmed by CI.

Firefox applies a `<table>`'s `clip-path` to the inner grid box of the
table, whereas Chrome and Safari apply it to the outer table wrapper
box. A `<caption>` is rendered in the outer table wrapper box, so it is
not clipped by the table itself in Firefox and stays visible.

`width`/`height: 1px` plus `overflow: hidden` don't hide it either,
because a table can't shrink below the size of its own content.

Clip the caption explicitly so that `sr-only` hides it in every engine.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7ee9c5ce-96b9-4d2b-a163-a6e5a4a4eb38
@snmsoodan
snmsoodan requested a review from a team as a code owner September 28, 2026 21:34
@greptile-apps

greptile-apps Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium risk] Adjusts CSS utility for screen-reader-only styling.

The PR appears safe to merge, with a limited caption-styling conflict worth addressing.

Reviews (2) · Last reviewed commit: "Reset the caption clipping in `not-sr-on..."

Comment thread packages/tailwindcss/src/utilities.ts
Comment thread packages/tailwindcss/tests/ui.spec.ts
@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Walkthrough

The sr-only utility applies clip-path: inset(50%) to direct child captions. The not-sr-only utility resets the caption’s clip-path to none. Utility fixture tests and browser tests cover these rules, including responsive behavior.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: 🔵 Low · up to 9f1ff

The caption fix is mergeable with awareness that Firefox’s rendered behavior is not directly asserted by the test.

Architecture Summary

Architecture risk: 🔵 Low · up to 9f1ff

The change affects 1 system.

Changed systems: packages/tailwindcss

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — packages/tailwindcss (library) was modified; 3 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in packages/tailwindcss/src/utilities.test.ts: The sr-only test expectation adds a caption rule with clip-path: inset(50%).
  • observed — Modified behavior in packages/tailwindcss/src/utilities.test.ts: The not-sr-only test expectation adds a caption rule with clip-path: none.
  • observed — Modified behavior in packages/tailwindcss/src/utilities.ts: sr-only adds a direct-child caption rule that applies clip-path: inset(50%).
  • observed — Modified behavior in packages/tailwindcss/src/utilities.ts: not-sr-only adds a direct-child caption rule that resets clip-path to none.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR meets issue #20510. The sr-only > caption rule applies clip-path: inset(50%) and directly hides the caption in Firefox. The caption remains in place, so the table accessible name does not c…
Out of Scope Changes check ✅ Passed The changes stay within issue #20510 and its responsive reset requirement. The source changes implement caption clipping and restoration. The snapshot and UI tests verify those changes. No unrelated c…
Title check ✅ Passed The title clearly and concisely describes the main change: ensuring that sr-only also hides a table caption.
Description check ✅ Passed The description directly explains the Firefox issue, the CSS fix, the not-sr-only reset, and the related tests.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/tailwindcss/tests/ui.spec.ts (1)

1536-1536: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the caption is not painted in Firefox.

The current assertion checks only the computed clip-path. It can pass while Firefox still paints the caption. Add a Firefox-scoped rendered-output assertion, such as a screenshot check, to cover the clipping behavior.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 7088cb35-f3c3-45f0-94e9-f569975659be

📥 Commits

Reviewing files that changed from the base of the PR and between fa81d69 and 2f04b40.

📒 Files selected for processing (3)
  • packages/tailwindcss/src/utilities.test.ts
  • packages/tailwindcss/src/utilities.ts
  • packages/tailwindcss/tests/ui.spec.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment thread packages/tailwindcss/src/utilities.ts
`sr-only` clips `> caption` so that a table's caption is hidden in Firefox,
where a table's own `clip-path` does not clip it. `not-sr-only` has to undo
that, otherwise `sr-only md:not-sr-only` keeps the revealed table's caption
clipped. Covered by a new UI test that checks both breakpoints.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7ee9c5ce-96b9-4d2b-a163-a6e5a4a4eb38
@snmsoodan

Copy link
Copy Markdown
Author

Note for the reviewer: #20521, opened two days earlier, fixes the same issue. I only found it while re-checking the issue for linked PRs, and it should be weighed alongside this one — the difference is where the clipping is re-applied:

  • Fix sr-only table caption visibility in Firefox (#20510) #20521 puts it in preflight.css as :where(table.sr-only, .sr-only > table) > caption { clip-path: inherit; overflow: hidden }, so it applies when preflight is included.
  • This PR puts it on the sr-only utility itself (sr-only > caption { clip-path: inset(50%) }), so it works with preflight: false, with a bare @import "tailwindcss/utilities.css", and, importantly, it can be undone by not-sr-only, which the preflight route cannot do for a sr-only md:not-sr-only table (the caption rule would keep clipping after the table is revealed).

Either way, please take whichever you prefer; happy to close this one if #20521 is the shape you want.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
packages/tailwindcss/tests/ui.spec.ts (1)

1535-1537: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a Firefox rendering assertion for the table caption.

CI already runs this test with the Firefox Playwright project. The test only checks the computed clip-path, so it does not establish that Firefox hides the rendered caption. Add an assertion for the caption’s rendered visibility.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 61207af5-0915-4dfc-898f-70e472461b4e

📥 Commits

Reviewing files that changed from the base of the PR and between 2f04b40 and 9f1ff79.

📒 Files selected for processing (3)
  • packages/tailwindcss/src/utilities.test.ts
  • packages/tailwindcss/src/utilities.ts
  • packages/tailwindcss/tests/ui.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/tailwindcss/src/utilities.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

['clip-path', 'none'],
['white-space', 'normal'],
// `sr-only` also clips the caption of a table, so undo that here
() => styleRule('& > caption', [decl('clip-path', 'none')]),

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.

P2 Caption clipping is overridden When a table has not-sr-only but was never sr-only, this rule still sets its caption’s clip-path to none. .not-sr-only > caption is more specific than a normal utility on the caption, so an intentionally clipped caption loses its styling.

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.

sr-only does not hide a <table>'s <caption> in Firefox

1 participant