Skip to content

feat(ui): replace custom toggle with native input switch polyfill#2998

Open
tomayac wants to merge 1 commit into
npmx-dev:mainfrom
tomayac:feat/input-switch-polyfill
Open

feat(ui): replace custom toggle with native input switch polyfill#2998
tomayac wants to merge 1 commit into
npmx-dev:mainfrom
tomayac:feat/input-switch-polyfill

Conversation

@tomayac

@tomayac tomayac commented Jul 4, 2026

Copy link
Copy Markdown

Summary

  • Replaces the hand-rolled toggle styling in Settings/Toggle.client.vue with the native <input type="checkbox" switch> element.
  • Adds input-switch-polyfill for browsers that don't yet support the native switch attribute, loaded only when needed, kept live-synced with the accent color and color-mode via a MutationObserver.
image

Split out of #2982 per review feedback to keep that PR focused on PWA/WCO/badging.

Test plan

  • pnpm test:unit — 1673/1673 passing
  • pnpm run test:types — passing
  • vp lint — 0 errors
  • knip — clean

Uses the new <input type="checkbox" switch> element, polyfilled via
input-switch-polyfill for browsers that don't support it yet, kept
live-synced with the accent color and color-mode changes.
@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
docs.npmx.dev Ready Ready Preview, Comment Jul 4, 2026 2:16pm
npmx.dev Ready Ready Preview, Comment Jul 4, 2026 2:16pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
npmx-lunaria Ignored Ignored Jul 4, 2026 2:16pm

Request Review

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedinput-switch-polyfill@​1.12.07310010091100

View full report

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR simplifies the toggle input's styling to rely on the native HTML switch input type with accent-color, adds a client-side Nuxt plugin that polyfills switch support and synchronises accent colour via a CSS custom property using a MutationObserver, and wires in the corresponding stylesheet and npm dependency.

Changes

Native switch toggle and polyfill

Layer / File(s) Summary
Toggle component styling simplification
app/components/Settings/Toggle.client.vue
The toggle's checkbox input replaces extensive pseudo-element/checked Tailwind classes with minimal focus-visible classes and inline accent-color styling.
Input switch polyfill plugin
app/plugins/input-switch-polyfill.client.ts
A new client plugin feature-detects native switch support, dynamically imports the polyfill when absent, computes and applies --switch-accent from computed accent-color, and re-syncs it via a MutationObserver on document attribute changes.
Stylesheet and dependency wiring
nuxt.config.ts, package.json
The polyfill's CSS file is added to the Nuxt css array, and input-switch-polyfill version 1.12.0 is added as a runtime dependency.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant NuxtPlugin as input-switch-polyfill.client.ts
  participant Polyfill as input-switch-polyfill
  participant DOM

  Browser->>NuxtPlugin: plugin init (defineNuxtPlugin)
  NuxtPlugin->>NuxtPlugin: check HTMLInputElement.prototype.switch
  alt switch unsupported
    NuxtPlugin->>Polyfill: dynamic import()
  end
  NuxtPlugin->>DOM: query input.switch elements
  NuxtPlugin->>DOM: read accent-color from first switch
  NuxtPlugin->>DOM: set --switch-accent on all switches
  DOM-->>NuxtPlugin: MutationObserver triggers on style/class change
  NuxtPlugin->>NuxtPlugin: re-run syncSwitchAccent
Loading

Possibly related PRs

  • npmx-dev/npmx.dev#2742: Both PRs modify app/components/Settings/Toggle.client.vue's input class/styling behaviour.

Suggested reviewers: gameroman, graphieros

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely summarises the main change: replacing the custom toggle with an input switch polyfill.
Description check ✅ Passed The description is directly related to the changeset and accurately explains the toggle replacement and polyfill support.
✨ 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.

@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

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!

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

e18e dependency analysis

No dependency warnings found.

@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 (2)
app/components/Settings/Toggle.client.vue (1)

57-63: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use :id shorthand.

Vue 3.4+ supports same-name shorthand binding; :id="id" can be simplified to :id.

Based on learnings, "In Vue 3.4 and later, you can use same-name shorthand for attribute bindings... Apply this shorthand in .vue components (notably in Settings/Toggle.client.vue)".

✏️ Suggested tweak
-      :id="id"
+      :id
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/components/Settings/Toggle.client.vue` around lines 57 - 63, The toggle
input in Toggle.client.vue still uses the longer same-name binding for the id
attribute; update the checkbox element to use Vue 3.4+ same-name shorthand for
the existing id binding. Locate the input in the Toggle component and simplify
the current :id binding without changing any other props or behavior.

Source: Learnings

app/plugins/input-switch-polyfill.client.ts (1)

1-4: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid awaiting the polyfill import in the plugin chain
defineNuxtPlugin(async () => { ... await import('input-switch-polyfill') }) still serialises later plugins while that import is in flight. This only affects browsers that lack native switch support, so the delay is limited to those clients; if that matters, switch to object syntax with parallel: true or defer the import with void import(...).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/plugins/input-switch-polyfill.client.ts` around lines 1 - 4, The plugin
in defineNuxtPlugin is still awaiting the input-switch-polyfill import, which
blocks later plugins for clients without native switch support. Update
input-switch-polyfill.client.ts to avoid awaiting the dynamic import in the
plugin chain by using object syntax with parallel: true or by deferring it with
void import('input-switch-polyfill') while keeping the
HTMLInputElement.prototype check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/plugins/input-switch-polyfill.client.ts`:
- Around line 9-24: The syncSwitchAccent logic only runs on html style/class
mutations, so newly mounted input.switch elements can miss --switch-accent until
something else changes. Update the input-switch-polyfill.client.ts plugin so
syncSwitchAccent is invoked once immediately after setup (on import/mount)
and/or extend the MutationObserver on document.documentElement to also watch
childList changes so late-added switches are resynced.

---

Nitpick comments:
In `@app/components/Settings/Toggle.client.vue`:
- Around line 57-63: The toggle input in Toggle.client.vue still uses the longer
same-name binding for the id attribute; update the checkbox element to use Vue
3.4+ same-name shorthand for the existing id binding. Locate the input in the
Toggle component and simplify the current :id binding without changing any other
props or behavior.

In `@app/plugins/input-switch-polyfill.client.ts`:
- Around line 1-4: The plugin in defineNuxtPlugin is still awaiting the
input-switch-polyfill import, which blocks later plugins for clients without
native switch support. Update input-switch-polyfill.client.ts to avoid awaiting
the dynamic import in the plugin chain by using object syntax with parallel:
true or by deferring it with void import('input-switch-polyfill') while keeping
the HTMLInputElement.prototype check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a08a862e-e2fd-49d3-abf0-bc5be2643953

📥 Commits

Reviewing files that changed from the base of the PR and between e731a54 and 2a549a9.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • app/components/Settings/Toggle.client.vue
  • app/plugins/input-switch-polyfill.client.ts
  • nuxt.config.ts
  • package.json

Comment on lines +9 to +24
const syncSwitchAccent = () => {
const switches = document.querySelectorAll<HTMLInputElement>('input.switch')
const [first] = switches
if (!first) return
// All switches share the same cascade; read from the first one.
const color = getComputedStyle(first).getPropertyValue('accent-color').trim()
if (!color || color === 'auto') return
for (const el of switches) {
el.style.setProperty('--switch-accent', color)
}
}

new MutationObserver(syncSwitchAccent).observe(document.documentElement, {
attributes: true,
attributeFilter: ['style', 'class'],
})

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does the input-switch-polyfill npm package automatically detect and upgrade input[switch] elements added to the DOM after initial load, or only elements present at import time?

💡 Result:

The input-switch-polyfill package does not appear to automatically detect and upgrade input[switch] elements added to the DOM after the initial page load [1][2]. The polyfill is designed to progressively enhance existing checkbox elements that utilize the switch attribute [1][3]. It functions by applying styles and managing accessibility roles for elements present when the polyfill is initialized [3][2]. Documentation and implementation patterns for the package focus on initial conditional loading to prevent a Flash of Unstyled Content (FOUC), rather than observing dynamic DOM mutations [1][2]. There is no evidence in the project's documentation or source code structure of a MutationObserver or similar mechanism to monitor for dynamically injected elements [2][4][5][6][7][8].

Citations:


Re-sync on mount: syncSwitchAccent() only runs on html style/class mutations, so switches mounted later can miss --switch-accent until an unrelated mutation occurs. Call it once after import, or watch childList changes too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/plugins/input-switch-polyfill.client.ts` around lines 9 - 24, The
syncSwitchAccent logic only runs on html style/class mutations, so newly mounted
input.switch elements can miss --switch-accent until something else changes.
Update the input-switch-polyfill.client.ts plugin so syncSwitchAccent is invoked
once immediately after setup (on import/mount) and/or extend the
MutationObserver on document.documentElement to also watch childList changes so
late-added switches are resynced.

tomayac added a commit to tomayac/npmx.dev that referenced this pull request Jul 4, 2026
…ate PRs

Per review feedback, keeps this PR focused on PWA installability, WCO,
and app badging. The Share button and native switch polyfill now live
in npmx-dev#2997 and npmx-dev#2998 respectively.
@ghostdevv ghostdevv added the needs discussion An idea that needs more discussion to understand the scope and impact. label Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs discussion An idea that needs more discussion to understand the scope and impact.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants