Skip to content

feat: keyboard shortcuts switcher in Settings#1684

Merged
danielroe merged 13 commits intonpmx-dev:mainfrom
alex-key:feat/kbd-shortcuts-switcher
Feb 27, 2026
Merged

feat: keyboard shortcuts switcher in Settings#1684
danielroe merged 13 commits intonpmx-dev:mainfrom
alex-key:feat/kbd-shortcuts-switcher

Conversation

@alex-key
Copy link
Contributor

🔗 Linked issue

Resolves #1537

🧭 Context

In order to meet a11y requirements we should allow to disable custom keyboard shortcuts, which might conflict with other browser/OS shortcuts.

From Issue:

If we want to keep shortcuts, the easiest way to meet this requirement is to add a mechanism to turn them off. This should also hide the keyboard hints on the page.

  • Add a setting to disable keyboard shortcuts to the settings page.
  • Add a note to the keyboard shortcuts modals that links directly to the setting.
  • Conditionally render the keyboard hints based on the setting.

📚 Description

Basically checklist above describes changes. Added e2e to check for correct behavior on disabled shortcuts (last screenshot below).

Also see ss below for reference.

@knowler Since <kbd> rendering became <ClientOnly> it might cause layout shift (buttons in header). Please comment if this is an issue.

image image image

disable-kbd-shrtct-header-shift

@vercel
Copy link

vercel bot commented Feb 27, 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 27, 2026 2:40pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 27, 2026 2:40pm
npmx-lunaria Ignored Ignored Feb 27, 2026 2:40pm

Request Review

@alex-key alex-key changed the title Feat/kbd shortcuts switcher Keyboard shortcuts switcher in Settings Feb 27, 2026
@github-actions
Copy link

github-actions bot commented Feb 27, 2026

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
lunaria/files/en-GB.json Localization changed, will be marked as complete. 🔄️
lunaria/files/en-US.json Source changed, localizations will be marked as outdated.
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@alex-key alex-key changed the title Keyboard shortcuts switcher in Settings feat: Keyboard shortcuts switcher in Settings Feb 27, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR implements a feature toggle mechanism to disable keyboard shortcuts throughout the application to meet WCAG 2.2 Success Criterion 2.1.4. A new keyboardShortcuts boolean setting is added to the settings system with a default value of true. All keyboard event handlers across components are updated to check this setting before executing their logic. A new settings section provides users a toggle to disable keyboard shortcuts. The keyboard shortcuts modal now links to the settings page. Keyboard hint UI elements conditionally render based on the setting. Supporting internationalisation strings and comprehensive E2E and unit tests validate the functionality.

Possibly related PRs

Suggested reviewers

  • whitep4nth3r
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description directly addresses the linked issue #1537 and clearly describes the implementation of a keyboard shortcuts toggle setting, modal note, and conditional rendering of keyboard hints.
Linked Issues check ✅ Passed The PR successfully implements all three coding requirements from issue #1537: a settings toggle to disable keyboard shortcuts, a note linking from the modal to the setting, and conditional rendering of keyboard hints based on the setting.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the objectives in linked issue #1537. The composable, component updates, translations, and tests all support the keyboard shortcuts toggle feature without introducing unrelated modifications.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 3

🧹 Nitpick comments (3)
app/components/Link/Base.vue (1)

117-125: Consider reserving shortcut badge space to reduce hydration shift.

<ClientOnly> removes the <kbd> during SSR and inserts it on hydration, which can nudge neighbouring header controls. A fixed-size placeholder when ariaKeyshortcuts exists would keep layout stable.

app/components/Button/Base.vue (1)

30-30: Consider extracting the composable call to the top level of setup.

Invoking useKeyboardShortcuts() inside a computed getter is unconventional. Composables are typically called at the top level of <script setup> to ensure proper reactive context and lifecycle handling.

The current implementation works because import.meta.client guards the call on the server, but for clarity and adherence to Vue conventions, consider:

♻️ Suggested refactor
+const keyboardShortcuts = import.meta.client ? useKeyboardShortcuts() : shallowRef(false)
+const keyboardShortcutsEnabled = computed(() => keyboardShortcuts.value)
-const keyboardShortcutsEnabled = computed(() => import.meta.client && useKeyboardShortcuts().value)
test/e2e/interactions.spec.ts (1)

264-273: Consider adding a test for the 'c' shortcut when disabled.

For completeness, you might want to add a test verifying that the 'c' shortcut (compare) also does not navigate when shortcuts are disabled. This would mirror the enabled test at lines 155-165.

🧪 Optional test to add
test('"c" (package) does not navigate to compare when shortcuts are disabled', async ({
  page,
  goto,
}) => {
  await goto('/package/vue', { waitUntil: 'hydration' })

  await page.keyboard.press('c')

  await expect(page).toHaveURL(/\/package\/vue$/)
})

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ed4254 and 8506dd2.

📒 Files selected for processing (15)
  • app/app.vue
  • app/components/AppFooter.vue
  • app/components/AppHeader.vue
  • app/components/Button/Base.vue
  • app/components/Compare/PackageSelector.vue
  • app/components/Link/Base.vue
  • app/composables/useSettings.ts
  • app/pages/package/[[org]]/[name].vue
  • app/pages/settings.vue
  • i18n/locales/en.json
  • i18n/schema.json
  • lunaria/files/en-GB.json
  • lunaria/files/en-US.json
  • test/e2e/interactions.spec.ts
  • test/nuxt/composables/use-settings.spec.ts

@alex-key alex-key changed the title feat: Keyboard shortcuts switcher in Settings feat: keyboard shortcuts switcher in Settings Feb 27, 2026
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.

🧹 Nitpick comments (1)
app/components/Link/Base.vue (1)

118-126: Consider reserving space for the client-only <kbd> hint to reduce layout shift.

Because the key hint only appears after hydration, link/button content can shift horizontally. A small fallback placeholder in ClientOnly would minimise CLS in headers and dense layouts.

♻️ Suggested tweak
-    <ClientOnly>
+    <ClientOnly>
       <kbd
         v-if="keyboardShortcutsEnabled && ariaKeyshortcuts"
         class="ms-2 inline-flex items-center justify-center size-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
         aria-hidden="true"
       >
         {{ ariaKeyshortcuts }}
       </kbd>
+      <template `#fallback`>
+        <span
+          v-if="ariaKeyshortcuts"
+          class="ms-2 inline-block size-4"
+          aria-hidden="true"
+        />
+      </template>
     </ClientOnly>

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8506dd2 and 89c89bc.

📒 Files selected for processing (8)
  • app/components/AppFooter.vue
  • app/components/Compare/PackageSelector.vue
  • app/components/Link/Base.vue
  • i18n/locales/en.json
  • i18n/schema.json
  • lunaria/files/en-GB.json
  • lunaria/files/en-US.json
  • test/nuxt/composables/use-settings.spec.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • i18n/locales/en.json
  • test/nuxt/composables/use-settings.spec.ts
  • app/components/Compare/PackageSelector.vue
  • i18n/schema.json
  • app/components/AppFooter.vue

@codecov
Copy link

codecov bot commented Feb 27, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 4 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/app.vue 0.00% 2 Missing ⚠️
app/pages/package/[[org]]/[name].vue 0.00% 0 Missing and 1 partial ⚠️
app/pages/settings.vue 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

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

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89c89bc and 77bcb72.

📒 Files selected for processing (2)
  • app/components/AppFooter.vue
  • test/nuxt/composables/use-settings.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/nuxt/composables/use-settings.spec.ts

<i18n-t keypath="shortcuts.disable_shortcuts" tag="span" scope="global">
<template #settings>
<NuxtLink
:to="{ name: 'settings' }"
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

Link should target the keyboard-shortcuts section directly.

Line 103 currently routes to the settings page root only. To meet the “direct to setting” objective, point this link to the keyboard shortcuts section anchor instead of the page top.

Suggested change
-                    :to="{ name: 'settings' }"
+                    :to="{ name: 'settings', hash: '#keyboard-shortcuts' }"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
:to="{ name: 'settings' }"
:to="{ name: 'settings', hash: '#keyboard-shortcuts' }"

Copy link
Member

@knowler knowler left a comment

Choose a reason for hiding this comment

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

Nice work. I do think we should address the layout shift issue. I’m not sure if there’s a way to access the setting early (e.g. in a blocking way in the <head>) and then use CSS show/hide the shortcuts? There could be other ways to address the issue (e.g. creating the layouts in a way that contents don’t cause other things to shift; ensuring heights aren’t affected by the presence of the shortcuts).

@danielroe
Copy link
Member

tada! no more layout shift 🚀

@danielroe danielroe added this pull request to the merge queue Feb 27, 2026
Merged via the queue into npmx-dev:main with commit 41f16b5 Feb 27, 2026
14 checks passed
@alex-key
Copy link
Contributor Author

Thank you for the help, Daniel

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.

Add mechanism to turn off keyboard shortcuts (WCAG Level A requirement)

3 participants