vue-router-newtab
v1.0.2
Published
Cmd/Ctrl+click support for newTab router.push() navigation for Vue 3 + Vue Router 4
Downloads
3,655
Maintainers
Readme
New Tab Router
A Vue 3 + Vue Router 4 package that adds intelligent navigation behavior, specifically Cmd/Ctrl+click functionality to programmatic router.push() calls.
✨ Features
- 🎯 Smart Navigation: Automatically detects Cmd/Ctrl key presses during
router.push()calls - 🆕 New Tab Support: Opens routes in new tabs when modifier keys are pressed
- 🔧 Highly Configurable: Custom behaviors, callbacks, and route patterns
- 📱 Cross-Platform: Works on macOS (Cmd), Windows/Linux (Ctrl)
- 🛡️ Type Safe: Full TypeScript support with comprehensive type definitions
- 🚀 Zero Breaking Changes: Non-intrusive addition of new tab functionality to existing router
- 📦 Tree Shakeable: Optimized bundle size with ESM support
- 🧪 Well Tested: Comprehensive test coverage with Vitest and Playwright
🚀 Quick Start
Installation
npm install vue-router-newtab
# or
yarn add vue-router-newtab
# or
pnpm add vue-router-newtabBasic Usage
import { createRouter, createWebHistory } from 'vue-router';
import { newTabRouter } from 'vue-router-newtab';
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/contact', component: Contact },
],
});
// Enhance the router with Cmd/Ctrl+click support
newTabRouter(router);
// Now your existing router.push() calls work intelligently!
// Cmd/Ctrl + router.push('/about') = opens in new tab
// Normal router.push('/about') = normal navigationUsing with unplugin-vue-router
If you're using unplugin-vue-router for file-based routing, you need to import the type declarations in your main setup file:
// main.ts or router setup file
import 'vue-router-newtab/unplugin-vue-router.d.ts';
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import { newTabRouter } from 'vue-router-newtab';
// Your router setup with unplugin-vue-router
const router = createRouter({
history: createWebHistory(),
routes: [], // Routes are auto-generated by unplugin-vue-router
});
// Enhance the router with Cmd/Ctrl+click support
newTabRouter(router);This import ensures that TypeScript recognizes the enhanced router.push() method with the additional options when using unplugin-vue-router's typed routing.
In Your Components
<template>
<div>
<button @click="navigateToAbout">About (Cmd/Ctrl+click for new tab)</button>
<button @click="forceNewTab">Force New Tab</button>
</div>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router';
const router = useRouter();
const navigateToAbout = () => {
// This will open in new tab if Cmd/Ctrl is pressed
router.push('/about');
};
const forceNewTab = () => {
// This will always open in new tab
router.push('/about', { forceNewTab: true });
};
const conditionalNewTab = () => {
// This will only open in new tab if Cmd/Ctrl is pressed
router.push('/about', { newTab: true });
};
</script>📖 API Reference
newTabRouter(router, config?)
Adds new tab functionality to a Vue Router instance with intelligent navigation behavior.
Parameters:
router: Router- The Vue Router instance to support newTab behaviourconfig?: NewTabRouterConfig- Optional configuration object
Returns: NewTabRouter - The router instance with new tab functionality
Configuration Options
interface NewTabRouterConfig {
/** Enable Cmd/Ctrl+click detection (default: true) */
enableCtrlClick?: boolean;
/** Enable debug logging (default: false) */
debugMode?: boolean;
}Enhanced Push Options
interface EnhancedPushOptions {
/** Force opening in new tab regardless of modifier key */
forceNewTab?: boolean;
/** Open in new tab only if modifier key is pressed (false prevents new tab behavior) */
newTab?: boolean;
}🎛️ Advanced Usage
Debug Mode
newTabRouter(router, {
debugMode: process.env.NODE_ENV === 'development',
});Per-Call Customization
// Force new tab for specific calls
router.push('/external-link', { forceNewTab: true });
// Conditional new tab (only if modifier key is pressed)
router.push('/optional-new-tab', { newTab: true });
// Prevent new tab behavior for specific calls
router.push('/normal-navigation', { newTab: false });🔧 TypeScript Support
The package provides comprehensive TypeScript support with full type definitions:
import type {
NewTabRouterConfig,
EnhancedPushOptions,
NewTabRouter,
} from 'vue-router-newtab';
// Your router is now fully typed
const router: NewTabRouter = newTabRouter(
createRouter({
/* ... */
})
);
// newTab push method with full type safety
router.push('/about', { forceNewTab: true });🧪 Testing
Unit Tests
npm run testCoverage
npm run test:coverageE2E Tests
npm run test:e2e🌍 Browser Support
- ✅ Chrome 88+
- ✅ Firefox 85+
- ✅ Safari 14+
- ✅ Edge 88+
📦 Bundle Size
- ESM: ~3.2KB gzipped
- CJS: ~3.5KB gzipped
🚨 Important Notes
SSR Compatibility
The new tab router automatically detects server-side environments and skips new tab functionality to prevent SSR errors:
// Safe to use in SSR - will be skipped automatically
newTabRouter(router);Memory Management
The new tab router automatically cleans up event listeners when the router is destroyed. For manual cleanup:
import { destroyNewTabRouter } from 'vue-router-newtab';
// Clean up when needed
destroyNewTabRouter(router);Security Considerations
- New tabs are opened with
noopener,noreferrerfor security - External URLs are detected and handled appropriately
- Popup blockers are handled gracefully with fallback to normal navigation
🔄 Migration Guide
From Existing Projects
The new tab router is designed to be non-intrusive. Your existing code will work without changes:
// Before
router.push('/about');
// After (same code, enhanced behavior)
newTabRouter(router);
router.push('/about'); // Now supports Cmd/Ctrl+click!🤝 Contributing
Contributions are welcome! Please read our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/sjmc11/vue-router-newtab.git
# Install dependencies
npm install
# Run tests
npm run test
# Build the package
npm run build📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Vue.js team for the amazing framework
- Vue Router team for the excellent routing solution
- All contributors who help make this project better
📞 Support
Made with ❤️ for the Vue.js community
