Vize

use-route-query

Built-in QueryParsers.

Package @vizejs/composable/use-route-query
Own the source vize lib pull composable:use-route-query
Runtime exports queryParsers, oneOf, useRouteQuery, useRouteParams
Gzip budget 1536 B

Minimal setup

Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).

vp install @vizejs/composable

Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.

import { queryParsers, oneOf, useRouteQuery, useRouteParams } from "@vizejs/composable/use-route-query";

Try it

Keep the selected tab in the URL query

Read and write one typed query parameter so a view can be shared and restored.

Open the interactive example

What to observe: Choose pricing and the query becomes tab=pricing. Choose overview to remove it, because it is the default.

This example uses a local route object; in an app pass useRoute() and navigate with router.replace({ query }). oneOf rejects unknown values.

Compare the initial and interacted states
Keep the selected tab in the URL query: initial state
Initial state
Keep the selected tab in the URL query: state after the verified interactions
After the verified interactions

Copy the example

Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.

<script setup lang="ts">
import { computed, reactive } from "vue";
import { oneOf, useRouteQuery } from "@vizejs/composable/use-route-query";

// In an app, pass `useRoute()` and navigate with `router.replace({ query })`.
const route = reactive({ params: {}, query: {} as Record<string, string> });
const queryText = computed(() => new URLSearchParams(route.query).toString() || "(none)");
const tab = useRouteQuery(route, "tab", {
  parse: oneOf(["overview", "pricing", "faq"] as const),
  default: "overview",
  navigate: (query) => {
    route.query = { ...(query as Record<string, string>) };
  },
});
</script>

<template>
  <div class="composable-example">
    <p>Keep the selected tab in the URL query so the view can be shared and restored.</p>
    <div role="tablist" aria-label="Product sections">
      <button
        v-for="name in ['overview', 'pricing', 'faq'] as const"
        :key="name"
        role="tab"
        type="button"
        :aria-selected="tab === name"
        @click="() => (tab = name)"
      >
        {{ name }}
      </button>
    </div>
    <output aria-live="polite">Query: {{ queryText }}</output>
  </div>
</template>

Runtime contract

Utility Category Stability SSR Hydration Cleanup Targets Host globals Uses
oneOf state experimental safe stable none web, server, worker, native, desktop, terminal — —
useRouteQuery state experimental safe stable none web, server, worker, native, desktop, terminal — —
useRouteParams state experimental safe stable none web, server, worker, native, desktop, terminal — —

API

queryParsers

Built-in QueryParsers.

const queryParsers

oneOf

Parser accepting only the given literal values.

function oneOf<const Values extends readonly string[]>( values: Values, ): QueryParser<Values[number]>
useRouteQuery(route, "sort", { parse: oneOf(["new", "top"]), default: "new" });

useRouteQuery

Typed, optionally writable view of one query parameter. The value type is inferred from parse and default: with a default the ref never holds undefined. Pass navigate to make the ref writable; writes build the next query (keeping every other key), drop the key when the value equals the default, and hand it to navigate, which is where the router integration pushes or replaces the URL. Works with any route object exposing query, including @vizejs/router's RouteMatch. Pure derived state: SSR-safe and hydration-stable (it reads the matched route only).

function useRouteQuery( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options: StringQueryOptions & { readonly default: string; readonly navigate: (query: RouteQueryRecord) => void; }, ): WritableComputedRef<string>
const page = useRouteQuery(match, "page", {
  parse: queryParsers.integer,
  default: 1,
  navigate: (query) => navigateTo(router.resolve(match.value.name, match.value.params, { query })),
});
page.value += 1;

useRouteQuery

function useRouteQuery( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options: StringQueryOptions & { readonly navigate: (query: RouteQueryRecord) => void }, ): WritableComputedRef<string | undefined, string | undefined>

useRouteQuery

function useRouteQuery( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options: StringQueryOptions & { readonly default: string }, ): ComputedRef<string>

useRouteQuery

function useRouteQuery( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options?: StringQueryOptions, ): ComputedRef<string | undefined>

useRouteQuery

function useRouteQuery<Value>( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options: UseRouteQueryOptions<Value> & { readonly default: NoInfer<Value>; readonly navigate: (query: RouteQueryRecord) => void; }, ): WritableComputedRef<Value>

useRouteQuery

function useRouteQuery<Value>( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options: UseRouteQueryOptions<Value> & { readonly navigate: (query: RouteQueryRecord) => void }, ): WritableComputedRef<Value | undefined, Value | undefined>

useRouteQuery

function useRouteQuery<Value>( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options: UseRouteQueryOptions<Value> & { readonly default: NoInfer<Value> }, ): ComputedRef<Value>

useRouteQuery

function useRouteQuery<Value>( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options: UseRouteQueryOptions<Value>, ): ComputedRef<Value | undefined>

useRouteQuery

function useRouteQuery( route: MaybeRefOrGetter<RouteLocationLike>, key: string, options: ErasedQueryOptions = {}, ): ComputedRef<unknown> | WritableComputedRef<unknown>

useRouteParams

Typed view of the matched route's path params. Without a key, returns all params (typed from the route table when the route comes from @vizejs/router). With a key, returns that param; with a parser, the parsed value. Pure derived state: SSR-safe.

function useRouteParams<Route extends RouteLocationLike>( route: MaybeRefOrGetter<Route>, ): ComputedRef<RouteParamsOf<Route>>
const params = useRouteParams(match); // ComputedRef<{ readonly id: string }>
const id = useRouteParams(match, "id", Number); // ComputedRef<number>

useRouteParams

function useRouteParams<Route extends RouteLocationLike, Key extends keyof Route["params"]>( route: MaybeRefOrGetter<Route>, key: Key, ): ComputedRef<Route["params"][Key]>

useRouteParams

function useRouteParams< Route extends RouteLocationLike, Key extends keyof Route["params"], Value, >( route: MaybeRefOrGetter<Route>, key: Key, parse: (raw: Route["params"][Key]) => Value, ): ComputedRef<Value>

useRouteParams

function useRouteParams( route: MaybeRefOrGetter<RouteLocationLike>, ...args: readonly [] | readonly [PropertyKey] | readonly [PropertyKey, (raw: unknown) => unknown] ): ComputedRef<unknown>

Types

RouteLocationLike

Structural subset of a matched route. @vizejs/router's RouteMatch satisfies it, so its inferred params type flows through without this package depending on the router.

Member Type Description
params object Decoded path params.
query RouteQueryRecord Parsed query.

UseRouteQueryOptions

Options for useRouteQuery.

Member Type Description
parse? QueryParser<Value> Converts the raw value.
serialize? QuerySerializer<Value> Converts a written value back into the query.
navigate? (query: RouteQueryRecord) => void Performs the navigation for a write, receiving the complete next query. Without it the returned ref is read-only.
omitDefault? boolean Remove the key instead of writing it when the value equals the default.