Skip to content

Conversation

@iiio2
Copy link
Contributor

@iiio2 iiio2 commented Feb 7, 2026

this actually related to this PR #1133

Current we've implemented back navigation only when it is necessary. When we go to any page like https://npmx.dev/about or https://npmx.dev/compare, we firstly see the back button then it disappears - a flash of the back button before it disappears. So, I think it is like a UX thing. So, that's why I've tried to improve it.

@vercel
Copy link

vercel bot commented Feb 7, 2026

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

Project Deployment Actions Updated (UTC)
docs.npmx.dev Ready Ready Preview, Comment Feb 8, 2026 1:39am
npmx.dev Ready Ready Preview, Comment Feb 8, 2026 1:39am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
npmx-lunaria Ignored Ignored Feb 8, 2026 1:39am

Request Review

@vercel
Copy link

vercel bot commented Feb 7, 2026

@iiio2 is attempting to deploy a commit to the serhalp's projects Team on Vercel.

A member of the Team first needs to authorize it.

@codecov
Copy link

codecov bot commented Feb 7, 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!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 7, 2026

📝 Walkthrough

Walkthrough

Adds a new composable useCanGoBack() that returns a reactive Ref<boolean> set on mount by checking router.options.history.state.back. Replaces direct router history checks in four pages (about, compare, privacy, settings) with useCanGoBack() and changes back-button rendering from v-show to v-if, so the back button is conditionally mounted only when navigation history exists.

Possibly related PRs

  • npmx-dev/npmx.dev PR 1133: Introduced inline v-show checks against router.options.history.state.back for back-button visibility that this change refactors into a composable.
  • npmx-dev/npmx.dev PR 941: Added back-button logic in app/pages/compare.vue using router history state, which is replaced here by useCanGoBack().
  • npmx-dev/npmx.dev PR 936: Implemented router-backed back buttons across pages now gated by the new useCanGoBack() composable.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description clearly explains the purpose: fixing a UX issue where the back button briefly appears and disappears when navigating to pages, and the changes directly address this problem.

✏️ 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

No actionable comments were generated in the recent review. 🎉


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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
app/pages/compare.vue (1)

118-123: ⚠️ Potential issue | 🟡 Minor

Remove per-button focus-visible utility class.

The project uses a global focus-visible rule for buttons; keep this button consistent and rely on the global styling instead.

♻️ Suggested change
-            class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0"
+            class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded shrink-0"

Based on learnings: In the npmx.dev project, ensure that focus-visible styling for button and select elements is implemented globally in app/assets/main.css with the rule: button:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }. Do not apply per-element inline utility classes like focus-visible:outline-accent/70 on these elements in Vue templates or components.

app/pages/privacy.vue (1)

30-35: ⚠️ Potential issue | 🟡 Minor

Remove per-button focus-visible utility class.

Use the global focus-visible styling for buttons rather than inline utilities on this button.

♻️ Suggested change
-            class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0"
+            class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded shrink-0"

Based on learnings: In the npmx.dev project, ensure that focus-visible styling for button and select elements is implemented globally in app/assets/main.css with the rule: button:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }. Do not apply per-element inline utility classes like focus-visible:outline-accent/70 on these elements in Vue templates or components.

app/pages/settings.vue (1)

52-56: ⚠️ Potential issue | 🟡 Minor

Remove per-button focus-visible utility class.

Rely on the global button focus-visible rule for this Back button.

♻️ Suggested change
-            class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0 p-1.5 -mx-1.5"
+            class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded shrink-0 p-1.5 -mx-1.5"

Based on learnings: In the npmx.dev project, ensure that focus-visible styling for button and select elements is implemented globally in app/assets/main.css with the rule: button:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }. Do not apply per-element inline utility classes like focus-visible:outline-accent/70 on these elements in Vue templates or components.

app/pages/about.vue (1)

53-58: ⚠️ Potential issue | 🟡 Minor

Remove per-button focus-visible utility class.

Stick to the global focus-visible styling for buttons to keep accessibility styling consistent.

♻️ Suggested change
-            class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0"
+            class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded shrink-0"

Based on learnings: In the npmx.dev project, ensure that focus-visible styling for button and select elements is implemented globally in app/assets/main.css with the rule: button:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }. Do not apply per-element inline utility classes like focus-visible:outline-accent/70 on these elements in Vue templates or components.

Comment on lines 1 to 7
export function useCanGoBack() {
const canGoBack = ref(false)

if (import.meta.client) {
const router = useRouter()
canGoBack.value = router.options.history.state.back !== null
}
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 | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Vue Router 4 router.options.history.state undefined null documentation

💡 Result:

In Vue Router 4, the history implementation you pass to createRouter({ history }) implements RouterHistory, which has a state: HistoryState property (documented, but marked Alpha in the API docs). (router.vuejs.org)

Why router.options.history.state can be undefined / null

  • router.options is not the recommended public surface to read from. Even though it exists, it’s not the API the docs point you to for “history state”.
  • Browser window.history.state can be null (e.g., before anything has called pushState/replaceState, or depending on how the entry was created). Vue Router also stores its own navigation info in history.state, and the docs warn you to preserve/merge it if you ever call history.replaceState() yourself. (typeerror.org)

What the documentation does recommend using

  • If your goal is to attach/read state for navigations, use the documented state option in navigation:
    • router.push({ ..., state: { ... } }) / router.replace({ ..., state: { ... } }) (router.vuejs.org)
  • Vue Router’s direction (per core discussion) is to expose this as route.state (reactive), rather than having people poke at router.options.history.state or raw window.history.state. (github.com)

Practical guidance

  • Don’t rely on router.options.history.state for app logic.
  • Use navigation state (router.push/replace) and (where available in your version) read it from route.state; otherwise, read window.history.state but assume it may be null and that Vue Router also uses it internally. (typeerror.org)

Citations:


🏁 Script executed:

find . -name "useCanGoBack.ts" -type f

Repository: npmx-dev/npmx.dev

Length of output: 94


🏁 Script executed:

cat -n ./app/composables/useCanGoBack.ts

Repository: npmx-dev/npmx.dev

Length of output: 345


🏁 Script executed:

rg "useCanGoBack" --type ts --type tsx -A 3 -B 3

Repository: npmx-dev/npmx.dev

Length of output: 88


🏁 Script executed:

rg "useCanGoBack" -A 3 -B 3

Repository: npmx-dev/npmx.dev

Length of output: 1595


Use the browser History API or Vue Router's navigation state; router.options.history.state is not a documented public API and accessing .back is unsafe.

router.options.history.state is an internal, undocumented property and not recommended. The proper approach in Vue Router 4 is to either:

  1. Use window.history.state directly (assuming it may be null), or
  2. Use the state option in router.push()/router.replace() and read from route.state

Beyond the API concern, the current code accesses .back without guarding against undefined or null, which will fail if the browser history state is not initialised. If you must inspect window.history.state, use optional chaining: Boolean(window.history.state?.back).

@danielroe danielroe changed the title chore(ux): consistent back navigation chore(ui): consistent back navigation Feb 7, 2026
@danielroe danielroe added this pull request to the merge queue Feb 8, 2026
Merged via the queue into npmx-dev:main with commit 5f9ef8f Feb 8, 2026
17 checks passed
@iiio2
Copy link
Contributor Author

iiio2 commented Feb 8, 2026

Thanks @danielroe . 😊

@iiio2 iiio2 deleted the chore/consistent-back-navigation branch February 8, 2026 10:07
@coderabbitai coderabbitai bot mentioned this pull request Feb 9, 2026
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.

2 participants