Skip to content

Examples

Basic Form Component

A complete Vue component demonstrating different query parameter types using queryRef:

vue
<script setup lang="ts">
import { serializers, queryRef } from 'vue-qs';

const name = queryRef('name', { defaultValue: '', parse: String });

const itemCount = queryRef('itemCount', { defaultValue: 0, codec: serializers.numberCodec });

const isPublished = queryRef('isPublished', {
  defaultValue: false,
  codec: serializers.booleanCodec,
});

const tags = queryRef<string[]>('tags', {
  defaultValue: [],
  codec: serializers.createArrayCodec(serializers.stringCodec),
});
</script>

<template>
  <div class="form-container">
    <h2>Basic Form Example</h2>

    <div class="field">
      <label>Name:</label>
      <input v-model="name" placeholder="Your name" />
    </div>

    <div class="field">
      <label>Item Count:</label>
      <input v-model="itemCount" type="number" placeholder="Item count" />
    </div>

    <div class="field">
      <label>
        <input v-model="isPublished" type="checkbox" />
        Is Published
      </label>
    </div>

    <div class="field">
      <label>Tags:</label>
      <select v-model="tags" multiple>
        <option v-for="tag in ['vue', 'javascript', 'frontend', 'backend']" :key="tag" :value="tag">
          {{ tag }}
        </option>
      </select>
    </div>

    <div class="output">
      <h3>Current State:</h3>
      <pre>{{ JSON.stringify({ name, itemCount, isPublished, tags }, null, 2) }}</pre>
    </div>
  </div>
</template>

Mixed queryRef and queryReactive Component

A component demonstrating both queryRef and queryReactive together:

vue
<script setup lang="ts">
import { computed } from 'vue';
import { serializers, queryRef, queryReactive } from 'vue-qs';

// Individual queryRef for category selection
const category = queryRef<'books' | 'music' | 'games'>('category', {
  defaultValue: 'books',
  codec: serializers.createEnumCodec(['books', 'music', 'games'] as const),
});

// queryReactive for grouped filter state
const filters = queryReactive({
  search: { defaultValue: '' },
  page: { defaultValue: 1, codec: serializers.numberCodec },
  minPrice: { defaultValue: 0, codec: serializers.numberCodec },
  maxPrice: { defaultValue: 1000, codec: serializers.numberCodec },
  inStock: { defaultValue: false, codec: serializers.booleanCodec },
});

// Computed property that combines both states
const searchSummary = computed(() => ({
  category: category.value,
  totalFilters: Object.values(filters).filter(Boolean).length,
  ...filters,
}));

// Method to reset all filters at once
const resetFilters = () => {
  filters.search = '';
  filters.page = 1;
  filters.minPrice = 0;
  filters.maxPrice = 1000;
  filters.inStock = false;
};

// Method to apply quick filters
const applyQuickFilter = (type: 'cheap' | 'expensive' | 'available') => {
  switch (type) {
    case 'cheap':
      filters.minPrice = 0;
      filters.maxPrice = 50;
      filters.inStock = true;
      break;
    case 'expensive':
      filters.minPrice = 500;
      filters.maxPrice = 1000;
      break;
    case 'available':
      filters.inStock = true;
      filters.page = 1;
      break;
  }
};
</script>

<template>
  <div class="search-container">
    <h2>Product Search</h2>

    <!-- Category selection using queryRef -->
    <div class="section">
      <h3>Category (queryRef)</h3>
      <div class="category-buttons">
        <button
          v-for="cat in ['books', 'music', 'games']"
          :key="cat"
          :class="{ active: category === cat }"
          @click="category = cat"
        >
          {{ cat.charAt(0).toUpperCase() + cat.slice(1) }}
        </button>
      </div>
    </div>

    <!-- Filters using queryReactive -->
    <div class="section">
      <h3>Filters (queryReactive)</h3>

      <div class="field">
        <label>Search:</label>
        <input v-model="filters.search" placeholder="Search products..." />
      </div>

      <div class="field">
        <label>Page:</label>
        <input v-model="filters.page" type="number" min="1" />
      </div>

      <div class="field-group">
        <div class="field">
          <label>Min Price:</label>
          <input v-model="filters.minPrice" type="number" min="0" />
        </div>

        <div class="field">
          <label>Max Price:</label>
          <input v-model="filters.maxPrice" type="number" min="0" />
        </div>
      </div>

      <div class="field">
        <label>
          <input v-model="filters.inStock" type="checkbox" />
          In Stock Only
        </label>
      </div>
    </div>

    <!-- Quick actions -->
    <div class="section">
      <h3>Quick Filters</h3>
      <div class="quick-buttons">
        <button @click="applyQuickFilter('cheap')">Cheap Items</button>
        <button @click="applyQuickFilter('expensive')">Expensive Items</button>
        <button @click="applyQuickFilter('available')">Available Items</button>
        <button @click="resetFilters()" class="reset">Reset All</button>
      </div>
    </div>

    <!-- State display -->
    <div class="output">
      <h3>Current Search State:</h3>
      <pre>{{ JSON.stringify(searchSummary, null, 2) }}</pre>
    </div>
  </div>
</template>

Released under the MIT License.