Documentation v1.1.0

Preview Purchase

Overview

Quick Search is an exclusive advanced component of Good that provides a flexible and powerful UI component to manage and handle layouts related to search. Quick Search also comes with multiple custom hook points to allow advanced users to bind custom JS or search logic to control and manipulate our Quick Search component.
The Quick Search component is a frontend only solution that manages element display orders and event triggers to show/hide certain layers. However, the search logic backend functionality is not included.

Usage

Quick Search  hooks are globally included in our scripts bundle, however, initialization is manually controlled and is required to be included.
<link href="assets/css/style.bundle.css" rel="stylesheet" type="text/css"/>
<script src="assets/js/scripts.bundle.js"></script>

Initialization

  • The Quick Search component is a highly robust and flexible frontend solution that comes with number of HTML elements to provide a rapid search layout. Quick Search starts with a simple divelement that houses a number of HTML attributes to control and configure the Quick Search component. See below for more info.
  • Quick Search structure comes in a few layers.
    • Main Wrapper
    • Toggle Button
    • Main Content Element
    • Main Content Inner Wrapper
    • Input Form
    • Search Suggestion
    • Search Preference
    • Search Advanced Options
    • Search Results
    • Empty Search
  • Each search UI HTML element within the main wrapper can be identified by the data-kt-search-elementHTML attribute with a specific value. For example, data-kt-search-element="toggle"indicates that the current HTML element is a Toggle Button. See below for more info.
  • Quick Search uses our extended Bootstrap's utility classes for styling.
  • Quick Search instances can also be controlled programmatically. See below for more info.

Basic Layout

Here's a basic example of our Quick Search.
In this demo, we're simulating the search results by randomly showing and hiding the search results layer on keypress within the input field.
image
Pic
Emma Smith Art Director
M
Melody Macy Marketing Analytic
Pic
Max Smith Software Enginer
Pic
Sean Bean Web Developer
Pic
Brian Cox UI/UX Designer
C
Mikaela Collins Head Of Marketing
Pic
Francis Mitcham Software Arcitect
O
Olivia Wild System Admin
N
Neil Owen Account Manager
Pic
Dan Wilson Web Desinger
No users found
Try to search by username, full name or email...
image
var processs = function(search) {
    var timeout = setTimeout(function() {
        var number = KTUtil.getRandomInt(1, 6);

        // Hide recently viewed
        suggestionsElement.classList.add("d-none");

        if (number === 3) {
            // Hide results
            resultsElement.classList.add("d-none");
            // Show empty message 
            emptyElement.classList.remove("d-none");
        } else {
            // Show results
            resultsElement.classList.remove("d-none");
            // Hide empty message 
            emptyElement.classList.add("d-none");
        }                  

        // Complete search
        search.complete();
    }, 1500);
}

var clear = function(search) {
    // Show recently viewed
    suggestionsElement.classList.remove("d-none");
    // Hide results
    resultsElement.classList.add("d-none");
    // Hide empty message 
    emptyElement.classList.add("d-none");
}    

// Input handler
const handleInput = () => {
    // Select input field
    const inputField = element.querySelector("[data-kt-search-element="input"]");

    // Handle keyboard press event
    inputField.addEventListener("keydown", e => {
        // Only apply action to Enter key press
        if(e.key === "Enter"){
            e.preventDefault(); // Stop form from submitting
        }
    });
}

// Elements
element = document.querySelector('#kt_docs_search_handler_basic');

if (!element) {
    return;
}

wrapperElement = element.querySelector("[data-kt-search-element="wrapper"]");
suggestionsElement = element.querySelector("[data-kt-search-element="suggestions"]");
resultsElement = element.querySelector("[data-kt-search-element="results"]");
emptyElement = element.querySelector("[data-kt-search-element="empty"]");

// Initialize search handler
searchObject = new KTSearch(element);

// Search handler
searchObject.on("kt.search.process", processs);

// Clear handler
searchObject.on("kt.search.clear", clear);

// Handle select
KTUtil.on(element, "[data-kt-search-element="customer"]", "click", function() {
    //modal.hide();
});

// Handle input enter keypress
handleInput();
<!--begin::Main wrapper-->
<div 
    id="kt_docs_search_handler_basic" 
    
    data-kt-search-keypress="true"
    data-kt-search-min-length="2"
    data-kt-search-enter="true"     
    data-kt-search-layout="inline">

    <!--begin::Input Form-->
    <form data-kt-search-element="form" class="w-100 position-relative mb-5" autocomplete="off"> 
        <!--begin::Hidden input(Added to disable form autocomplete)-->
        <input type="hidden"/>
        <!--end::Hidden input-->

        <!--begin::Icon-->
            <!--begin::Svg Icon | path: icons/duotune/general/gen021.svg-->
        <!--end::Icon-->

        <!--begin::Input-->
        <input type="text" class="form-control form-control-lg form-control-solid px-15"
            name="search"
            value=""
            placeholder="Search by username, full name or email..."
            data-kt-search-element="input"/>
        <!--end::Input-->

        <!--begin::Spinner-->
        <span class="position-absolute top-50 end-0 translate-middle-y lh-0 d-none me-5" data-kt-search-element="spinner">
            <span class="spinner-border h-15px w-15px align-middle text-gray-400"></span>
        </span>
        <!--end::Spinner-->

        <!--begin::Reset-->
        <span class="btn btn-flush btn-active-color-primary position-absolute top-50 end-0 translate-middle-y lh-0 me-5 d-none"
            data-kt-search-element="clear">
            
            <!--begin::Svg Icon | path: icons/duotune/arrows/arr061.svg-->
        </span>
        <!--end::Reset-->
    </form>
    <!--end::Form-->

    <!--begin::Wrapper-->
    <div class="py-5">                            
        <!--being::Search suggestion-->
        <div data-kt-search-element="suggestions">
            ...
        </div>
        <!--end::Suggestion wrapper-->

        <!--begin::Search results-->
        <div data-kt-search-element="results" class="d-none">
            ...
        </div>
        <!--end::Search results-->

        <!--begin::Empty search-->
        <div data-kt-search-element="empty" class="text-center d-none">
            ...
        </div>
        <!--end::Empty search-->        
    </div>
    <!--end::Wrapper-->
</div>
<!--end::Main wrapper-->

Menu Layout

This demo combines the Quick Search component with our menu component for unique interactive dropdown search UI component.
In this demo, we're simulating the search results by randomly showing and hiding the search results layer on keypress within the input field.
var processs = function(search) {
    var timeout = setTimeout(function() {
        var number = KTUtil.getRandomInt(1, 3);

        // Hide recently viewed
        mainElement.classList.add("d-none");

        if (number === 3) {
            // Hide results
            resultsElement.classList.add("d-none");
            // Show empty message 
            emptyElement.classList.remove("d-none");
        } else {
            // Show results
            resultsElement.classList.remove("d-none");
            // Hide empty message 
            emptyElement.classList.add("d-none");
        }                  

        // Complete search
        search.complete();
    }, 1500);
}

var clear = function(search) {
    // Show recently viewed
    mainElement.classList.remove("d-none");
    // Hide results
    resultsElement.classList.add("d-none");
    // Hide empty message 
    emptyElement.classList.add("d-none");
}    

var handlePreferences = function() {
    // Preference show handler
    preferencesShowElement.addEventListener("click", function() {
        wrapperElement.classList.add("d-none");
        preferencesElement.classList.remove("d-none");
    });

    // Preference dismiss handler
    preferencesDismissElement.addEventListener("click", function() {
        wrapperElement.classList.remove("d-none");
        preferencesElement.classList.add("d-none");
    });
}

var handleAdvancedOptionsForm = function() {
    // Show
    advancedOptionsFormShowElement.addEventListener("click", function() {
        wrapperElement.classList.add("d-none");
        advancedOptionsFormElement.classList.remove("d-none");
    });

    // Cancel
    advancedOptionsFormCancelElement.addEventListener("click", function() {
        wrapperElement.classList.remove("d-none");
        advancedOptionsFormElement.classList.add("d-none");
    });

    // Search
    advancedOptionsFormSearchElement.addEventListener("click", function() {
        
    });
}

// Elements
element = document.querySelector("#kt_docs_search_handler_menu");

if (!element) {
    return;
}

wrapperElement = element.querySelector("[data-kt-search-element="wrapper"]");
formElement = element.querySelector("[data-kt-search-element="form"]");
mainElement = element.querySelector("[data-kt-search-element="main"]");
resultsElement = element.querySelector("[data-kt-search-element="results"]");
emptyElement = element.querySelector("[data-kt-search-element="empty"]");

preferencesElement = element.querySelector("[data-kt-search-element="preferences"]");
preferencesShowElement = element.querySelector("[data-kt-search-element="preferences-show"]");
preferencesDismissElement = element.querySelector("[data-kt-search-element="preferences-dismiss"]");

advancedOptionsFormElement = element.querySelector("[data-kt-search-element="advanced-options-form"]");
advancedOptionsFormShowElement = element.querySelector("[data-kt-search-element="advanced-options-form-show"]");
advancedOptionsFormCancelElement = element.querySelector("[data-kt-search-element="advanced-options-form-cancel"]");
advancedOptionsFormSearchElement = element.querySelector("[data-kt-search-element="advanced-options-form-search"]");

// Initialize search handler
searchObject = new KTSearch(element);

// Search handler
searchObject.on("kt.search.process", processs);

// Clear handler
searchObject.on("kt.search.clear", clear);

// Custom handlers
handlePreferences();
handleAdvancedOptionsForm();
<!--begin::Main wrapper-->
<div id="kt_docs_search_handler_menu"
    class="d-flex align-items-stretch" 
    
    data-kt-search-keypress="true" 
    data-kt-search-min-length="2" 
    data-kt-search-enter="true" 
    data-kt-search-layout="menu" 
    
    data-kt-menu-trigger="auto" 
    data-kt-menu-overflow="false" 
    data-kt-menu-permanent="true" 
    data-kt-menu-placement="bottom-start">

    <!--begin::Search toggle-->
    <div class="d-flex align-items-center" data-kt-search-element="toggle" id="kt_header_search_toggle">
        <div class="btn btn-primary">
            Toggle Quick Search
        </div>
    </div>
    <!--end::Search toggle-->

    <!--begin::Menu-->
    <div data-kt-search-element="content" class="menu menu-sub menu-sub-dropdown p-7 w-325px w-md-375px">
        <!--begin::Wrapper-->
        <div data-kt-search-element="wrapper">
        <!--begin::Form-->
            <form data-kt-search-element="form" class="w-100 position-relative mb-3" autocomplete="off"> 
                <!--begin::Icon-->
                    <!--begin::Svg Icon | path: icons/duotune/general/gen021.svg-->
                <!--end::Icon-->
            
                <!--begin::Input-->
                <input type="text"
                    class="form-control form-control-flush ps-10"
                    name="search" 
                    value=""
                    placeholder="Search..." 
                    data-kt-search-element="input"/>
                <!--end::Input-->
            
                <!--begin::Spinner-->
                <span class="position-absolute top-50 end-0 translate-middle-y lh-0 d-none me-1"
                    data-kt-search-element="spinner">
                    <span class="spinner-border h-15px w-15px align-middle text-gray-400"></span>
                </span>
                <!--end::Spinner-->
            
                <!--begin::Reset-->
                <span class="btn btn-flush btn-active-color-primary position-absolute top-50 end-0 translate-middle-y lh-0 d-none"
                    data-kt-search-element="clear">
                    <!--begin::Svg Icon | path: icons/duotune/arrows/arr061.svg-->
                </span>
                <!--end::Reset-->
            
                <!--begin::Toolbar-->
                <div class="position-absolute top-50 end-0 translate-middle-y" data-kt-search-element="toolbar">
                    <!--begin::Preferences toggle-->
                    <div data-kt-search-element="preferences-show"
                        class="btn btn-icon w-20px btn-sm btn-active-color-primary me-1"
                        data-bs-toggle="tooltip"
                        title="Show search preferences">
                        <!--begin::Svg Icon | path: icons/duotune/coding/cod001.svg-->
                    </div>
                    <!--end::Preferences toggle-->
            
                    <!--begin::Advanced search toggle-->
                    <div data-kt-search-element="advanced-options-form-show"
                        class="btn btn-icon w-20px btn-sm btn-active-color-primary"
                        data-bs-toggle="tooltip"
                        title="Show more search options">
                        <!--begin::Svg Icon | path: icons/duotune/arrows/arr072.svg-->
                    </div>
                    <!--end::Advanced search toggle-->
                </div>
                <!--end::Toolbar-->
            </form>
            <!--end::Form-->

            <!--begin::Search results-->
            <div data-kt-search-element="results" class="d-none">
                ...
            </div>
            <!--end::Search results-->

            <!--begin::Main content element-->
            <div data-kt-search-element="main">
                ...
            </div>
            <!--end::Main content element-->

            <!--begin::Empty search-->
            <div data-kt-search-element="empty" class="text-center d-none">
                ...
            </div>
            <!--end::Empty search-->    
        </div>
        <!--end::Wrapper-->

        <!--begin::Search Advanced Options-->
        <div data-kt-search-element="advanced-options-form">
            ...
        </div>
        <!--end::Search Advanced Options-->

        <!--begin::Search Preference-->
        <div data-kt-search-element="preferences">
            ...
        </div>
        <!--end::Search Preference-->
    </div>
    <!--end::Menu-->
</div>
<!--end::Main wrapper-->

Responsive Layout

This demo showcases Search UI's responsive solution. It displays as a full inline input field on large screens, and converts into an icon toggle button on smaller screens.
In this demo, we're simulating the search results by randomly showing and hiding the search results layer on keypress within the input field.
var processs = function(search) {
    var timeout = setTimeout(function() {
        var number = KTUtil.getRandomInt(1, 3);

        // Hide recently viewed
        recentlyViewedElement.classList.add("d-none");

        if (number === 3) {
            // Hide results
            resultsElement.classList.add("d-none");
            // Show empty message 
            emptyElement.classList.remove("d-none");
        } else {
            // Show results
            resultsElement.classList.remove("d-none");
            // Hide empty message 
            emptyElement.classList.add("d-none");
        }                  

        // Complete search
        search.complete();
    }, 1500);
}

var clear = function(search) {
    // Show recently viewed
    recentlyViewedElement.classList.remove("d-none");
    // Hide results
    resultsElement.classList.add("d-none");
    // Hide empty message 
    emptyElement.classList.add("d-none");
}    

// Elements
element = document.querySelector("#kt_docs_search_handler_responsive");

if (!element) {
    return;
}

wrapperElement = element.querySelector("[data-kt-search-element="wrapper"]");
recentlyViewedElement = element.querySelector("[data-kt-search-element="recently-viewed"]");
resultsElement = element.querySelector("[data-kt-search-element="results"]");
emptyElement = element.querySelector("[data-kt-search-element="empty"]");
preferencesElement = element.querySelector("[data-kt-search-element="preferences"]");
preferencesShowElement = element.querySelector("[data-kt-search-element="preferences-show"]");
preferencesDismissElement = element.querySelector("[data-kt-search-element="preferences-dismiss"]");

// Initialize search handler
searchObject = new KTSearch(element);

// Search handler
searchObject.on("kt.search.process", processs);

// Clear handler
searchObject.on("kt.search.clear", clear);

// Preference show handler
preferencesShowElement.addEventListener("click", function() {
    wrapperElement.classList.add("d-none");
    preferencesElement.classList.remove("d-none");
});

// Preference dismiss handler
preferencesDismissElement.addEventListener("click", function() {
    wrapperElement.classList.remove("d-none");
    preferencesElement.classList.add("d-none");
});
}
<!--begin::Main wrapper-->
<div 
    id="kt_docs_search_handler_responsive" 
    class="d-flex align-items-center w-lg-400px"
    
    data-kt-search-keypress="true"
    data-kt-search-min-length="2"
    data-kt-search-enter="enter"     
    data-kt-search-layout="menu"
    data-kt-search-responsive="lg"
    
    data-kt-menu-trigger="auto" 
    data-kt-menu-permanent="true" 
    data-kt-menu-placement="bottom-start">

    <!--begin::Tablet and mobile search toggle-->
    <div data-kt-search-element="toggle" class="d-flex d-lg-none align-items-center">
        <div class="btn btn-icon btn-active-light-primary">
            <?php echo Theme::getSvgIcon("icons/duotune/general/gen021.svg", "svg-icon-1")?>
        </div>
    </div>
    <!--end::Tablet and mobile search toggle-->

    <!--begin::Form-->
    <form data-kt-search-element="form" class="d-none d-lg-block w-100 position-relative mb-5 mb-lg-0" autocomplete="off"> 
        <!--begin::Hidden input(Added to disable form autocomplete)-->
        <input type="hidden"/>
        <!--end::Hidden input-->

        <!--begin::Icon-->
        <?php echo Theme::getSvgIcon("icons/duotune/general/gen021.svg", "svg-icon-2 svg-icon-lg-1 svg-icon-gray-500 position-absolute top-50 translate-middle-y ms-5")?>
        <!--end::Icon-->

        <!--begin::Input-->
        <input type="text" class="form-control form-control-solid ps-14" name="search" value="" placeholder="Search..." data-kt-search-element="input"/>
        <!--end::Input-->

        <!--begin::Spinner-->
        <span class="position-absolute top-50 end-0 translate-middle-y lh-0 d-none me-6" data-kt-search-element="spinner">
            <span class="spinner-border h-15px w-15px align-middle text-gray-400"></span>
        </span>
        <!--end::Spinner-->

        <!--begin::Reset-->
        <span class="btn btn-flush btn-active-color-primary position-absolute top-50 end-0 translate-middle-y lh-0 me-5 d-none" data-kt-search-element="clear">
            <?php echo Theme::getSvgIcon("icons/duotune/arrows/arr061.svg", "svg-icon-2 svg-icon-lg-1 me-0")?>
        </span>
        <!--end::Reset-->
    </form>
    <!--end::Form-->

    <!--begin::Menu-->
    <div data-kt-search-element="content" class="menu menu-sub menu-sub-dropdown w-300px w-md-400px py-7 px-7 overflow-hidden">
        <!--begin::Wrapper-->
        <div data-kt-search-element="wrapper">
            <!--begin::Categories-->
            <div data-kt-search-element="categories">
                ...
            </div>
            <!--end::Categories-->

            <!--begin::Search results-->
            <div data-kt-search-element="results" class="d-none">
                ...
            </div>
            <!--end::Search results-->

            <!--begin::Recently viewed-->
            <div data-kt-search-element="recently-viewed">
                ...
            </div>
            <!--end::Recently viewed-->

            <!--begin::Empty search-->
            <div data-kt-search-element="empty" class="text-center d-none">
                ...
            </div>
            <!--end::Empty search-->  
        </div>
        <!--end::Wrapper-->

        <!--begin::Preferences-->
        <div data-kt-search-element="preferences"
            ...
        </div>
        <!--end::Preferences-->
    </div>
    <!--end::Menu-->
</div>
<!--end::Main wrapper-->

Markup Reference

Main wrapper HTML Attribute references
Quick Search  uses HTML attributes within the Main Wrapper to configure the frontend logic. Here are the references for each below
Name Type Description
data-kt-search-keypress optional Enable search on any keyboard keypress. Accepts trueor falsevalues.
data-kt-search-enter optional Enable search on any keyboard Enterkeypress. Accepts trueor falsevalues.
data-kt-search-responsive optional
Defines the responsive mode for the input field's position. Useful for an inline input field to display itself within a dropdown menu on mobile to save space. Accepts sm, md, lg, xland nullvalues.
For example: data-kt-search-responsive="lg"indicates that the Quick Search component input field will be displayed inline with the parent container from lgscreen sizes and above, and hidden (re-positioned into the dropdown menu) on smaller screens.
data-kt-search-min-length optional Defines the number of characters required before the search event is triggered. Accepts numericvalues.
data-kt-search-layout optional Defines Quick Search's layout type. Accepts inlineand menuvalues.
data-kt-search-show-on-focus optional Enables menu dropdown to show when the input field detects a focus event. Accepts trueor falsevalues.
HTML Attribute Identifiers references
Quick Search also use HTML attributes to identify the HTML elements that are used within the Main Wrapper. Here are the references for each below
Name Type Description
data-kt-search-element mandatory
Identifies the HTML element as a specific Quick Search element. All Quick Search elements must be added within the Main Wrapper. The main wrapper does not have a specific attribute to identify it. It's simply a wrapping divelement that wraps all Quick Search inner elements.
Here are the list of Quick Search elements available:
  • form
  • input
  • spinner
  • clear
  • toggle
  • content
  • toolbar
  • empty
  • results
  • suggestions
<div>
    <div data-kt-search-element="form">
        ...
        <input data-kt-search-element="input" />
        ...
    </div>
</div>

Methods

The following are Search UI's functionality methods for more control.
Name Description
Static Methods
getInstance(DOMElement element) Get the Search UI instance that has been created and returns the Search UI DOM element.
var searchElement = document.querySelector("#kt_search_example_1");
var search = KTSearch.getInstance(searchElement);
Public Methods
new KTSearch(DOMElement element) Initialize a new Quick Search control.
var searchElement = document.querySelector("#kt_search_control");
var search = new KTSearch(searchElement);
show Triggers the menu to show. Only applicable when data-kt-search-layoutis set to menu
search.show();
hide Triggers the menu to hide. Only applicable when data-kt-search-layoutis set to menu
search.hide();
update Updates the menu responsiveness. Only applicable when data-kt-search-layoutis set to menu
search.update();
search Triggers the search event to begin searching.
search.search();
complete Triggers the completed search event.
search.complete();
clear Clears the search input field and resets the Search UI.
search.clear();
isProcessing Returns trueor falseto indicate if there's a search event still running.
search.isProcessing();
getQuery Returns the Search UI input string.
search.getQuery();
getMenu Returns the Search UI menu element. Only applicable when data-kt-search-layoutis set to menu
search.getMenu();
getFormElement Returns the Search UI form element.
search.getFormElement();
getInputElement Returns the Search UI input field element.
search.getInputElement();
getContentElement Returns the Search UI content element.
search.getContentElement();
getElement Returns the Search UI element.
search.getElement();

Events

Below are few events for hooking into Quick Search's functionality.
Event Type Description
kt.search.process This event fires when search begins processing.
var searchElement = document.querySelector("#kt_search_example_1");
var search = KTSearch.getInstance(searchElement);
search.on("kt.search.process", function() {
    // console.log("kt.search.process event is fired");
});
kt.search.clear This event fires when search input field is about to be cleared.
var searchElement = document.querySelector("#kt_search_example_1");
var search = KTSearch.getInstance(searchElement);
search.on("kt.search.clear", function() {
    // console.log("kt.search.clear event is fired");
});
kt.search.cleared This event fires when search input field has been cleared.
var searchElement = document.querySelector("#kt_search_example_1");
var search = KTSearch.getInstance(searchElement);
search.on("kt.search.cleared", function() {
    // console.log("kt.search.cleared event is fired");
});
Learn & Get Inspired

Support at devs.keenthemes.com

Join our developers community to find answer to your question and help others. FAQs
Get Support
Documentation
From guides and how-tos, to live demos and code examples to get started right away.
Plugins & Components
Check out our 300+ in-house components and customized 3rd-party plugins.
Layout Builder
Build your layout, preview it and export the HTML for server side integration.
What's New
Latest features and improvements added with our users feedback in mind.
Buy now