Skip to content

fix: show copy buttons on touch devices and fix aria-label mismatch#2203

Closed
thealxlabs wants to merge 7 commits intonpmx-dev:mainfrom
thealxlabs:fix/copy-buttons-touch-and-aria
Closed

fix: show copy buttons on touch devices and fix aria-label mismatch#2203
thealxlabs wants to merge 7 commits intonpmx-dev:mainfrom
thealxlabs:fix/copy-buttons-touch-and-aria

Conversation

@thealxlabs
Copy link

🔗 Linked issue

resolves #1771

🧭 Context

Two related issues with CopyToClipboardButton: (1) copy buttons were hidden on touch devices because they relied on a CSS hover state that never fires on mobile, and (2) the button's aria-label could differ from its visible text, causing an accessibility label/content mismatch for screen readers.

📚 Description

  • Added @media (hover: none) CSS block to make copy buttons visible and interactable on touch-only devices, where hover is unavailable.
  • Fixed the aria-label computation so it defaults to copyText (the same string shown to sighted users) rather than a separate value, eliminating the WCAG label-content-name mismatch.

A regression test (test/nuxt/components/CopyToClipboardButton.spec.ts) verifies that:

  • aria-label matches the visible copyText when no explicit override is given
  • An explicit ariaLabelCopy prop takes precedence
  • The copied state correctly reflects copiedText in both label and visible text

@vercel
Copy link

vercel bot commented Mar 22, 2026

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

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Mar 22, 2026 8:36pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Mar 22, 2026 8:36pm
npmx-lunaria Ignored Ignored Mar 22, 2026 8:36pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 700928ce-00ad-4c79-8a95-5c7c3c91b0d6

📥 Commits

Reviewing files that changed from the base of the PR and between d0d6a82 and c0ca0bc.

📒 Files selected for processing (1)
  • app/components/CopyToClipboardButton.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/components/CopyToClipboardButton.vue

📝 Walkthrough

Walkthrough

Updated CopyToClipboardButton.vue ARIA-label fallback logic: buttonAriaLabelCopy now falls back to copyText when ariaLabelCopy is unset, and buttonAriaLabelCopied now falls back to copiedText when ariaLabelCopied is unset. Touch-device CSS was annotated with a comment under @media (hover: none); the .copyButton display: none rule remains unchanged. Added a Vitest test suite verifying aria-label behaviour across prop combinations and visible text. Minor CSS tweaks in Package/Header.vue: changed a container gap from gap-1 to gap-3 and adjusted an icon button vertical padding from py-1.25 to py-1.5.

Possibly related PRs

Suggested labels

needs review

Suggested reviewers

  • danielroe
  • alexdln
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR partially addresses #1771. The aria-label fix aligns with accessibility improvements, but the CSS change to show buttons on touch devices was later reverted (per commit message) due to target-size accessibility failure, leaving the core usability issue unresolved. Verify whether the @media (hover: none) CSS change is still present and functional. If reverted, re-evaluate the implementation to fix touch-device visibility without causing target-size violations or overlaps.
Out of Scope Changes check ⚠️ Warning The Package/Header.vue CSS adjustments (gap-1 to gap-3 and py-1.25 to py-1.5) are unrelated to the CopyToClipboardButton fixes or touch-device visibility issues described in #1771. Remove the unrelated CSS changes from Package/Header.vue or provide justification linking them to the touch-device or aria-label objectives.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description clearly relates to the changeset, addressing the two main issues: copy button visibility on touch devices and aria-label mismatch. The description aligns with the code changes in CopyToClipboardButton.vue and the test additions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit 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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9c13f9f9-c27b-4c3a-8f2e-310f4e119844

📥 Commits

Reviewing files that changed from the base of the PR and between 7f2fc1a and ed04748.

📒 Files selected for processing (2)
  • app/components/CopyToClipboardButton.vue
  • test/nuxt/components/CopyToClipboardButton.spec.ts

Comment on lines +55 to +59
const ariaLabel = button.attributes('aria-label') ?? ''
const visibleText = button.text()
// The aria-label should equal the visible text (not some other string)
expect(visibleText).toContain(ariaLabel)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Final mismatch test uses a weak/reversed assertion for its stated intent.

This can pass when aria-label is only a substring of visible text, so it does not reliably guard against label/content-name mismatch.

Proposed test tightening
-    const ariaLabel = button.attributes('aria-label') ?? ''
-    const visibleText = button.text()
-    // The aria-label should equal the visible text (not some other string)
-    expect(visibleText).toContain(ariaLabel)
+    const ariaLabel = (button.attributes('aria-label') ?? '').trim()
+    const visibleText = button.text().trim()
+    // The aria-label should equal the visible text (not some other string)
+    expect(ariaLabel).toBe(visibleText)

@codecov
Copy link

codecov bot commented Mar 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

…e violation

The @media (hover: none) block that made copy buttons always visible on
touch caused the absolutely-positioned button (top: 100%) to appear between
the package header and the sticky subheader, landing within 24px of the
provenance shield link and failing the target-size audit.

Revert to display: none on touch devices to eliminate the overlap.
@knowler
Copy link
Member

knowler commented Mar 22, 2026

Hey there, there already is an open PR (#998) to resolve this issue, even though it wasn’t linked (since it came before the issue was filed). We’re actively working on that one—just waiting for a dependency upgrade, so I will be closing this one. Thank you anyway!

@knowler knowler closed this Mar 22, 2026
@knowler knowler added the duplicate This issue or pull request already exists label Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

duplicate This issue or pull request already exists

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Copy buttons for commands are missed on mobile

2 participants