DatoCMS Site Search > Vue search widget

    Vue search widget

    In addition to the low-level API request presented in the previous section, our vue-datocms package also includes a Vue composable ready for rendering a full-featured Site Search widget on your website.

    You're in charge of the UI

    The composable only handles the logic: you are in complete control of how the form and the list of results render, down to the last component, class or style.

    Setup

    First of all, install the required npm packages in your Vue project:

    npm install --save @datocms/cma-client-browser vue-datocms

    You can then use the useSiteSearch composable like this:

    import { useSiteSearch } from 'vue-datocms';
    import { buildClient } from '@datocms/cma-client-browser';
    const client = buildClient({ apiToken: 'YOUR_API_TOKEN' });
    const { state, error, data } = useSiteSearch({
    client,
    buildTriggerId: '7497',
    // optional: by default fuzzy-search is not active
    fuzzySearch: true,
    // optional: you can omit it if you only have one locale, or you want to find results in every locale
    initialState: { locale: 'en' },
    // optional: defaults to 8 search results per page
    resultsPerPage: 10,
    })

    Please follow the vue-datocms documentation to read more about at the configuration options and the data returned by the hook.

    Complete example

    The following example shows a search page, including a very simple home-made pagination. You can build more advanced pagination widgets using the data.totalPages property to get the total number of pages, state.page to get the current page, and state.page = pageNumber to trigger a page change.

    <script setup lang="ts">
    import { useSiteSearch } from 'vue-datocms'
    import { buildClient } from '@datocms/cma-client-browser';
    const client = buildClient({ apiToken: 'YOUR_API_TOKEN' });
    const { state, error, data } = useSiteSearch({
    client,
    buildTriggerId: '7497',
    // optional: by default fuzzy-search is not active
    fuzzySearch: true,
    // optional: you can omit it you only have one locale, or you want to find results in every locale
    initialState: { locale: 'en' },
    // optional: defaults to 8 search results per page
    resultsPerPage: 9,
    })
    </script>
    <template>
    <div>
    <div class="bg-slate-200 py-4">
    <div class="container mx-auto">
    <input class="py-3 px-5 block w-full border-gray-200 rounded-full text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400" type="text" v-model="state.query" placeholder="Search: try something like &quot;vue&quot; or &quot;dato&quot;... " />
    </div>
    </div>
    <div class="bg-slate-100 py-4">
    <div class="container mx-auto py-4">
    <h1>{{ data.totalResults}} results</h1>
    </div>
    <div class="container mx-auto py-4 grid grid-cols-3 gap-4" v-if="data">
    <div v-for="result in data.pageResults" class="py-4">
    <div class="py-1">
    <a :href="result.url">
    <strong v-if="result.titleHighlights.length > 0">
    <template v-for="highlight in result.titleHighlights" class="py-1">
    <template v-for="piece in highlight">
    <mark v-if="piece.isMatch">{{ piece.text }}</mark>
    <template v-else>{{ piece.text }}</template>
    </template>
    </template>
    </strong>
    <strong v-else>{{ result.title }}</strong>
    </a>
    </div>
    <div v-for="highlight in result.bodyHighlights" class="py-1">
    <template v-for="piece in highlight">
    <mark v-if="piece.isMatch">{{ piece.text }}</mark>
    <template v-else>{{ piece.text }}</template>
    </template>
    </div>
    <details>
    <summary>Raw results</summary>
    <pre><code class="block whitespace-pre overflow-x-scroll">{{ JSON.stringify(result.raw, null, 2) }}</code></pre>
    </details>
    </div>
    </div>
    <div class="container mx-auto py-4">
    <div class="flex">
    <button v-if="state.page > 0" @click="state.page = state.page - 1" class="flex items-center px-4 py-2 mx-1 text-gray-700 transition-colors duration-300 transform bg-white rounded-md dark:bg-gray-800 dark:text-gray-200 hover:bg-blue-600 dark:hover:bg-blue-500 hover:text-white dark:hover:text-gray-200">
    Previous
    </button>
    <button v-if="state.page < data.totalPages" @click="state.page = state.page + 1" class="flex items-center px-4 py-2 mx-1 text-gray-700 transition-colors duration-300 transform bg-white rounded-md dark:bg-gray-800 dark:text-gray-200 hover:bg-blue-600 dark:hover:bg-blue-500 hover:text-white dark:hover:text-gray-200">
    Next
    </button>
    </div>
    </div>
    </div>
    </div>
    </template>