A simple JavaScript suggestion autocomplete app

on in AJAX and Fetching Data
Last modified on

JavaScript Search Suggestions

These days, I’ve been working on building a prediction search engine for real estate websites. I started with something small, and I am happy with what I got so far. I wouldn’t call this a prediction search engine, but a simple suggestion autocomplete feature. In its current form, it might be useful for someone. Here it goes.

First, I have the HTML structure, which has a basic design. Note, the suggestion-box element will hold all suggestions.

<div class="suggestion-box--wrapper">
    <div class="suggestion-input">
        <input type="text" placeholder="Type to search...">
        <div class="suggestion-box"></div>
        <div class="icon">🔍</div>
    </div>
</div>

Next, let’s style the dropdown, which only activates if a suggestion is found:

.suggestion-box--wrapper * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.suggestion-box--wrapper {
    max-width: 450px;
    margin: 150px auto;
}

.suggestion-box--wrapper .suggestion-input {
    background: #fff;
    width: 100%;
    border-radius: 5px;
    position: relative;
    box-shadow: 0 0 16px rgba(0, 0, 0, 0.12);
}

.suggestion-box--wrapper .suggestion-input input {
    height: 55px;
    width: 100%;
    outline: none;
    border: none;
    border-radius: 5px;
    padding: 0 60px 0 20px;
    font-size: 18px;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
}

.suggestion-box--wrapper .suggestion-input.active input {
    border-radius: 5px 5px 0 0;
}

.suggestion-box--wrapper .suggestion-input .suggestion-box {
    padding: 0;
    opacity: 0;
    pointer-events: none;
    max-height: 280px;
    overflow-y: auto;
}

.suggestion-box--wrapper .suggestion-input.active .suggestion-box {
    padding: 10px 8px;
    opacity: 1;
    pointer-events: auto;
}

.suggestion-box--wrapper .suggestion-box li {
    list-style: none;
    padding: 8px 12px;
    display: none;
    width: 100%;
    cursor: default;
    border-radius: 3px;
}

.suggestion-box--wrapper .suggestion-input.active .suggestion-box li {
    display: block;
}

.suggestion-box--wrapper .suggestion-box li:hover {
    background: #efefef;
}

.suggestion-box--wrapper .suggestion-input .icon {
    position: absolute;
    right: 0px;
    top: 0px;
    height: 55px;
    width: 55px;
    text-align: center;
    line-height: 55px;
    font-size: 20px;
    color: #644bff;
    cursor: pointer;
}

Next, is the actual engine. It’s very simple and requires no dependencies.

/**
 * Initializes the autocomplete functionality.
 * @param {HTMLElement} autoCompleteWrapper - The container for the autocomplete input.
 * @param {HTMLInputElement} searchInputElem - The input element for search.
 * @param {HTMLElement} autoCompleteBox - The container for autocomplete suggestions.
 * @param {string[]} suggestions - An array of suggestion words.
 */
function initAutocomplete(autoCompleteWrapper, searchInputElem, autoCompleteBox, suggestions) {
    searchInputElem.addEventListener("input", () => {
        const searchValue = searchInputElem.value.toLowerCase();
        const filteredWords = suggestions.filter(word => word.toLowerCase().startsWith(searchValue));
        suggestionWordsGenerator(filteredWords);
        autoCompleteWrapper.classList.toggle("active", !!searchValue);
    });

    /**
     * Generates suggestion words based on the user's input.
     * @param {string[]} wordsArray - An array of filtered suggestion words.
     */
    function suggestionWordsGenerator(wordsArray) {
        const listItemsArray = wordsArray.map(word => `<li>${word}</li>`);
        const customListItem = listItemsArray.length ? listItemsArray.join("") : `<li>${searchInputElem.value}</li>`;
        autoCompleteBox.innerHTML = customListItem;
        select();
    }

    /**
     * Handles the selection of a suggestion.
     */
    function select() {
        const allListItems = autoCompleteBox.querySelectorAll("li");
        allListItems.forEach(wordItem => {
            wordItem.addEventListener("click", event => {
                searchInputElem.value = event.target.textContent;
                autoCompleteWrapper.classList.remove("active");
            });
        });
    }
}

// Usage:
const autoCompleteWrapper = document.querySelector(".suggestion-box--wrapper .suggestion-input");
const searchInputElem = document.querySelector(".suggestion-box--wrapper input");
const autoCompleteBox = document.querySelector(".suggestion-box--wrapper .suggestion-box");

// Initialize autocomplete
initAutocomplete(autoCompleteWrapper, searchInputElem, autoCompleteBox, suggestions);

You may notice that the suggestions variable is not defined. This is where the magic comes from. The suggestions can be trained and changed, depending on the context and the website content. In my case, I have it built dynamically.

let suggestions = [
    "coastal properties",
    "coastal homes",
    "coastal houses",
    "waterfront properties",
    "waterfront apartments",
    "seaside properties",
    "detached house",
    "semi-detached house",
    "terraced house",
    "bungalow",
    "1 bedroom house",
    "2 bedroom house",
    "3 bedroom house",
    "4 bedroom house",
    "5 bedroom house",
    "6 bedroom house",
    "1 bedroom apartment",
    "2 bedroom apartment",
    "3 bedroom apartment",
    "4 bedroom apartment",
    "5 bedroom apartment",
    "6 bedroom apartment",
];

This way I can steer the user towards my main keywords (or services, or products).

See a demo below. Try to search one of the suggestions above. Note that actual searching does not work, the input field only illustrates the suggestion autocomplete.

🔍

Related posts