# Vue search widget

In addition to the [low-level API request](https://www.datocms.com/docs/site-search/base-integration.md) presented in the previous section, our [`vue-datocms`](https://github.com/datocms/vue-datocms/tree/master/src/composables/useSiteSearch) package also includes a Vue composable ready for rendering a full-featured Site Search widget on your website.

> [!POSITIVE] 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

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

You can then use the `useSiteSearch` composable like this:

```javascript
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,
  searchIndexId: '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](https://github.com/datocms/vue-datocms/tree/master/src/composables/useSiteSearch#initialization-options) and the [data returned by the hook](https://github.com/datocms/vue-datocms/tree/master/src/composables/useSiteSearch#returned-data).

### 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.

```html
<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,
  searchIndexId: '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>
```

## Related content in "DatoCMS Site Search"

- [Site Search Overview](https://www.datocms.com/docs/site-search.md)

- [Configuration](https://www.datocms.com/docs/site-search/configuration.md)
- [How the crawling works](https://www.datocms.com/docs/site-search/how-the-crawling-works.md)

- [Perform searches via API](https://www.datocms.com/docs/site-search/base-integration.md)
- [React search widget](https://www.datocms.com/docs/site-search/widget.md)

- [Vue search widget](https://www.datocms.com/docs/site-search/vue-search-widget.md)