npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-router-query-sync

v1.0.1

Published

Vue composable for syncing router query params with store

Downloads

25

Readme

vue-router-query-sync

demo

Effortlessly sync Vue Router query parameters with your store or local refs — no boilerplate.

npm version license


✨ What is this?

vue-router-query-sync is a tiny, fully-typed Vue 3 utility that keeps your reactive state (Pinia store fields or local refs) in sync with the current URL query string — both ways.

  • Changes in your store update the URL query.
  • Changes in the URL query update your store.
  • Batched updates prevent excessive router.replace calls.

💡 Why use this plugin?

  • 🔄 Keeps your app state and URL perfectly in sync — no more manual watchers or router.replace logic.
  • 🧠 Works with Pinia, local refs, or any reactive source.
  • 🧩 Handles multiple query keys and isolated contexts safely.
  • ⚙️ Fully typed with TypeScript and designed for Vue 3’s Composition API.
  • 🚀 Tiny footprint — optimized for production.

✅ Requirements

  • Vue 3
  • Vue Router 4

🚀 Installation

npm install vue-router-query-sync
# or
yarn add vue-router-query-sync
# or
pnpm add vue-router-query-sync

⚙️ Setup

// main.ts
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import routerQuerySync from 'vue-router-query-sync'
import App from './App.vue'

const router = createRouter({
  history: createWebHistory(),
  routes: []
})

createApp(App)
  .use(router)
  .use(routerQuerySync, { router })
  .mount('#app')

🧩 Basic Usage

You can use useQuerySync several times in one component.

Sync a value with a query param named tab:

  • Visiting ?tab=favorite sets tab.value = 'favorite'.
  • Changing tab.value = 'all' updates the URL to ?tab=all.
import { useQuerySync } from 'vue-router-query-sync'

const tab = ref<'favorite' | 'all'>('all')

useQuerySync(
  'tab',
  () => tab.value,
  (val) => (tab.value = val)
)

Multiple values

Sync a value with a query param named brands:

  • Visiting ?brands=lg%samsung sets brands.value = ['lg', 'samsung'].
  • Changing brands.value = ['lg'] updates the URL to ?brands=lg.
import { useQuerySync } from 'vue-router-query-sync'

const brands = [
    { value: 'lg', label: 'LG' },
    { value: 'samsung', label: 'Samsung' }
]

const selectedBrands = ref<string[]>([])

useQuerySync(
    'brands',
    () => {
        return selectedBrands.value.length > 0 ? selectedBrands.value.join('%') : null
    },
    (val) => {
        if (typeof val === 'string' && val) {
            selectedBrands.value = val.includes('%') ? val.split('%') : [val]
        } else {
            selectedBrands.value = []
        }
    }
)

🔧 API

function useQuerySync<T extends string | number>(
  key: string,
  get: () => T | null,
  set: (val: T) => void,
  options?: QuerySyncOptions
): void

type QuerySyncOptions = {
  deps?: Ref<unknown>[]
  context?: string
}
  • key: Query parameter name, e.g., 'tab'.
  • get: Function returning the current value from your store/ref. Return null to indicate “no value”.
  • set: Function that writes the value to your store/ref.
  • options.deps: Array of refs. If provided, the initial sync runs after any of these deps change (useful when state is populated asynchronously).
  • options.context: If the same query key may be used multiple times on the same page, provide a unique context to avoid collisions. The actual query key becomes ${context}_${key}.

❗ Important

If a page can have multiple components with the same query key, pass a unique context to avoid conflicts. The real key used in the URL will be ${context}_${key}. Otherwise, use unique keys per component.


🏷️ Context Example

If two widgets on the same page need a tab param, use unique contexts:

useQuerySync('tab', () => usersStore.tab, (v) => (usersStore.tab = v), { context: 'users' })
useQuerySync('tab', () => ordersStore.tab, (v) => (ordersStore.tab = v), { context: 'orders' })
// URL keys will be: users_tab and orders_tab

⏳ Delayed/Dependent Initialization

If your state becomes available later (e.g., after a request), delay the initial sync with deps:

const isReady = ref(false)

useQuerySync('sort', () => store.sort, (v) => (store.sort = v), { deps: [isReady] })

// Later when data is loaded:
isReady.value = true

📦 Exports

import routerQuerySync, { useQuerySync, replaceRouterQueue } from 'vue-router-query-sync'
  • default: Vue plugin to register with app.use(routerQuerySync, { router }).
  • useQuerySync: The composable described above.
  • replaceRouterQueue: Internal helper that batches query updates (exported in case you need manual batching).

Note: setRouter/getRouter are internal; prefer using the plugin install.


🔒 TypeScript

useQuerySync is fully typed. You can annotate the expected type if needed:

useQuerySync<number>('page', () => page.value, (v) => (page.value = v))

Values must be string or number.


📄 License

MIT © Ivan Chikachev