Search in page with Vue.js

Vue.js is an outstanding library we can use to build complex frontend UI and/or apps, but it can also be used to implement small features even if we're working with a legacy/old project.

Imaging a page (eg. built from a CMS) with a list of documents and we want to give the user the power of a search feature.

In Vue.js we should think, first of all, about data, so:

  1. Init the state (data) on mounted hook (populate the "documents" variable inxpecting and traversing the DOM
  2. Create a computed value that will drive UI refresh (the "searchResults" variable)
  3. Add a couple of methods to improve the accessibility (handleClickOnBody and handleKeyUp)

This is the final JavaScript code:

var searchApp = new Vue({
    el: '#searchapp',

    data: {
        documents: [],
        searchString: '',
        searchResultsVisible: true,
    },

    mounted: function () {
        docsEls = document.querySelectorAll('.list__item');
        for (const item of Array.from(docsEls)) {
            this.documents.push({
                text: item.querySelector('.list__item__description').innerHTML,
            });
        }

        document.documentElement.addEventListener(
            'click',
            this.handleClickOnBody
        );

        document.addEventListener('keyup', this.handleKeyUp);
    },

    computed: {
        activeSearchString: function () {
            return this.searchString.length >= 3 ? this.searchString : '';
        },

        searchResults: function () {
            if (this.activeSearchString !== '') {
                return this.documents.filter(
                    (d) =>
                        d.text
                            .toLowerCase()
                            .includes(this.activeSearchString.toLowerCase()) ==
                        true
                );
            } else {
                return [];
            }
        },
    },

    methods: {
        handleClickOnBody: function (e) {
            const target = e.target;
            const searchEl = this.$refs.searchEl;

            if (target !== searchEl && !searchEl.contains(target)) {
                this.searchResultsVisible = false;
            } else {
                this.searchResultsVisible = true;
            }
        },

        handleKeyUp: function (e) {
            if (e.key === 'Escape') {
                this.searchResultsVisible = false;
            }
        },
    },
});

Here you can find a complete CodePen