Sorry, no results found for "".

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:

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

You can then use the useSiteSearch composable like this:

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

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.

1
<script setup lang="ts">
2
3
import { useSiteSearch } from 'vue-datocms'
4
5
import { buildClient } from '@datocms/cma-client-browser';
6
7
const client = buildClient({ apiToken: 'YOUR_API_TOKEN' });
8
9
const { state, error, data } = useSiteSearch({
10
client,
11
buildTriggerId: '7497',
12
// optional: by default fuzzy-search is not active
13
fuzzySearch: true,
14
// optional: you can omit it you only have one locale, or you want to find results in every locale
15
initialState: { locale: 'en' },
16
// optional: defaults to 8 search results per page
17
resultsPerPage: 9,
18
})
19
20
</script>
21
22
<template>
23
<div>
24
<div class="bg-slate-200 py-4">
25
<div class="container mx-auto">
26
<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;... " />
27
</div>
28
</div>
29
<div class="bg-slate-100 py-4">
30
<div class="container mx-auto py-4">
31
<h1>{{ data.totalResults}} results</h1>
32
</div>
33
<div class="container mx-auto py-4 grid grid-cols-3 gap-4" v-if="data">
34
<div v-for="result in data.pageResults" class="py-4">
35
<div class="py-1">
36
<a :href="result.url">
37
<strong v-if="result.titleHighlights.length > 0">
38
<template v-for="highlight in result.titleHighlights" class="py-1">
39
<template v-for="piece in highlight">
40
<mark v-if="piece.isMatch">{{ piece.text }}</mark>
41
<template v-else>{{ piece.text }}</template>
42
</template>
43
</template>
44
</strong>
45
<strong v-else>{{ result.title }}</strong>
46
</a>
47
</div>
48
<div v-for="highlight in result.bodyHighlights" class="py-1">
49
<template v-for="piece in highlight">
50
<mark v-if="piece.isMatch">{{ piece.text }}</mark>
51
<template v-else>{{ piece.text }}</template>
52
</template>
53
</div>
54
<details>
55
<summary>Raw results</summary>
56
<pre><code class="block whitespace-pre overflow-x-scroll">{{ JSON.stringify(result.raw, null, 2) }}</code></pre>
57
</details>
58
</div>
59
</div>
60
<div class="container mx-auto py-4">
61
<div class="flex">
62
<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">
63
Previous
64
</button>
65
<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">
66
Next
67
</button>
68
</div>
69
</div>
70
</div>
71
</div>
72
</template>