Quick Search Widget (JS)
A Vanilla JS widget that enables users to perform real-time product searches with instant results, enhancing product discoverability and conversion.
Use this library when you want to display a widget without using a transpiler
like Babel and without using JSX. This library exports a htm
HTML factory
to assemble custom elements of the widget.
This widget library is version 0.1.18 and the API can change. Please specify exact version when installing.
Installation
Install @recombee/quick-search-widget-js@0.1.18
and
recombee-js-api-client
packages using your preferred NPM package manager.
This example is using pnpm
.
pnpm add @recombee/quick-search-widget-js@0.1.18 recombee-js-api-client
Always remember to apply the default CSS file distributed alongside the widget library, as shown in the examples.
Client Initialization
The widget loads recommendation data using Recombee API Client. Here is how to initialize the client with necessary configuration for a specific database:
import { } from "recombee-js-api-client";
const = "[database-id]";
const = "[database-public-token]";
const = "[database-region]";
export const = new (, , {
: ,
});
The Database Public Token can be found in the Admin UI Database Settings Page.
The widget also needs to be provided a createRequest
function, which
instantiates a client request class to define which data to pull from the
database. Use Scenario ID which can be found on Admin GUI
Database Scenarios Page.
Quick Search widget requires the createRequest
function to return a Batch
Request. For a basic case of single search request, always wrap it in a
batch.
import { type } from "@recombee/quick-search-widget-react";
import { , , } from "recombee-js-api-client";
const : = ({ }) => {
return new (
[
new (userId, , 5, {
: "search-items",
: true,
: true,
}),
new (userId, , 5, {
: "search-categories",
: true,
}),
],
{
: true,
},
);
};
Providing User ID
Each visitor of your website should be identified by a user identificator
(userId
) to correlate user activity and deliver best possible
recommendation performance. The userId
should preferrably originate from
your user's account details when the user is authenticated or as some
session-persistent random ID when they are anonymous. The SDK provides
utility which generates random user id and saves it to a cookie to cover the
latter case:
import { type } from "@recombee/quick-search-widget-react";
import { , , } from "recombee-js-api-client";
import { } from "@recombee/carousel-widget-react";
let : string | undefined;
if (authenticatedUserId) {
= authenticatedUserId;
} else {
= .();
}
const : = ({ }) => {
return new (
[
new (, , 5, {
: "search-items",
: true,
: true,
}),
new (, , 5, {
: "search-categories",
: true,
}),
],
{
: true,
},
);
};
Basic Example
The widget in this example uses the DefaultItem component to render each recommendation in a consistent layout.
The resulting widget is inserted into the element specified by the
container
field.
Values of the recommended items - such as title, image URL, or link URL - are
obtained from the API response and accessed via props.result?.values
.
Ensure that returnProperties: true is set in the request, and optionally use includedProperties to control which item properties are returned.
import {
,
,
,
,
,
,
,
,
} from "@recombee/quick-search-widget-js";
import "@recombee/quick-search-widget-js/dist/styles.css";
({
: "#widget-root",
: ,
: ,
: 3,
: "(min-width: 1000px)",
: "lg:w-[var(--qs-input-width)] lg:flex lg:justify-center",
: () =>
`<form className="flex w-[400px] text-[#374040]">
<${}
state=${.}
inputProps=${{
: `Search for "table"...`,
}}
/>
</form>`,
: () =>
`<button
...${..}
className="flex size-[38px] items-center justify-center rounded-sm bg-[#3bc4a1] text-white"
>
<${} />
</button>`,
: () =>
`<div
className="mt-1 flex h-full max-h-full min-h-0 flex-col rounded-sm bg-white text-[#374040] shadow-2xl lg:h-auto lg:max-w-[900px] lg:min-w-[600px]"
>
${!.. &&
`<form className="flex items-center gap-2 p-2">
<div className="flex-grow">
<${}
state=${.}
inputProps=${{
: `Search for "table"...`,
}}
/>
</div>
<button
...${..}
className="flex size-[38px] items-center justify-center"
>
<${} />
</button>
</form>`}
<div className="flex min-h-0 flex-grow flex-col">
<div className="px-4 py-4 pb-2 text-sm font-semibold text-[#3f91ff]">
Results
</div>
<div className="overflow-auto p-2">
${.
.(0)
.(
() =>
`<${}
key=${.}
href=${(
`${.?.}`,
.,
)}
image=${`<${}
className="size-16 overflow-hidden rounded-lg"
src=${`${.?.}`}
width=${600}
height=${400}
/>`}
primaryContent=${.?.}
secondaryContent=${.?.}
highlightedContent=${`USD ${.?.}`}
...${.}
/>`,
)}
</div>
</div>
</div>`,
});
Custom Template
You can customize the appearance and behavior of the Quick Search Widget by overriding its individual components:
- DropdownComponent – Renders the dropdown containing search results.
- InputComponent – Handles the search input field where users type their queries.
- TriggerComponent – Controls how the widget is opened on mobile devices.
The example also demonstrates how to make the search form submittable to a
dedicated results page using a submit
button.
import {
,
,
,
,
,
,
,
} from "@recombee/quick-search-widget-js";
import "@recombee/quick-search-widget-js/dist/styles.css";
({
: "#widget-root",
: ,
: ,
: 3,
: 1000,
: "(min-width: 1000px)",
: () =>
`<form
method="GET"
action="https://example.com/search"
target="_blank"
className="flex w-[400px] gap-2 text-[#374040]"
>
<div
className="relative flex flex-grow overflow-hidden rounded-lg border border-[#d9dbdb]"
>
<div
className="absolute flex size-[38px] items-center justify-center text-[#737979]"
>
<${} />
</div>
<input
name="q"
type="text"
className="block h-[39px] w-full indent-[38px] outline-hidden"
placeholder=${`Search for "table"...`}
...${..}
/>${.. &&
`<${}
className="rb:absolute rb:top-2.25 rb:right-2.25 rb:h-5 rb:w-5"
/>`}
</div>
<button
type="submit"
className="rounded-lg bg-[#3f91ff] px-5 py-2.5 text-sm font-medium text-white focus:ring-4 focus:ring-blue-300 focus:outline-hidden"
>
Search
</button>
</form>`,
: () =>
`<button
...${..}
className="flex size-[38px] items-center justify-center rounded-sm bg-[#3bc4a1] text-white"
>
<${} />
</button>`,
: () =>
`<div
className="mt-1 flex h-full max-h-full min-h-0 flex-col rounded-sm bg-white text-[#374040] shadow-2xl lg:h-auto lg:max-w-[900px] lg:min-w-[600px]"
>
${!.. &&
`<form className="flex items-center gap-2 p-2">
<div className="flex-grow">
<div
className="relative flex flex-grow overflow-hidden rounded-lg border border-[#d9dbdb]"
>
<div
className="flex size-[42px] items-center justify-center text-[#737979]"
>
<${} />
</div>
<input
type="text"
className="block w-full outline-hidden"
placeholder="Search in docs..."
...${..}
/>${.. &&
`<div
className="absolute top-2.5 right-2.5 h-5 w-5 animate-spin rounded-full border-2 border-dashed border-current text-[#d9dbdb] [--animate-spin:spin_3s_linear_infinite]"
/>`}
</div>
</div>
<button
...${..}
className="flex size-[38px] items-center justify-center"
>
<${} />
</button>
</form>`}
<div className="flex min-h-0 flex-grow flex-col">
<div className="px-4 py-4 pb-2 text-sm font-semibold text-[#3f91ff]">
Results
</div>
<div className="overflow-auto p-2">
${..(0).(
() =>
`<a
key=${.}
href=${(
`${.?.}`,
.,
)}
...${.}
className="flex items-center gap-4 rounded-sm p-2 outline-hidden hover:bg-[#f7f7f7] focus:bg-[#f7f7f7]"
><div>
<${}
className="size-16 overflow-hidden rounded-lg"
src=${`${.?.}`}
width=${600}
height=${400}
/>
</div>
<div className="rb:flex-grow">
<div
className="rb:font-semibold rb:text-nowrap rb:text-ellipsis rb:overflow-hidden"
>
${.?.}
</div>
<div
className="rb:text-[#737979] rb:text-nowrap rb:text-ellipsis rb:overflow-hidden"
>
${.?.}
</div>
</div>
<div
className="rb:font-bold rb:text-[#3f91ff] rb:text-nowrap rb:text-ellipsis rb:overflow-hidden"
>
${`USD ${.?.}`}
</div></a
>`,
)}
</div>
</div>
</div>`,
});
Multi-Type Search Results
You can use the Quick Search Widget to display multiple types of results. For example, showing not only items but also categories or brands using the Search Item Segments requests.
All search requests are sent together in a single Batch request.
import {
,
,
,
,
,
,
,
,
} from "@recombee/quick-search-widget-js";
import "@recombee/quick-search-widget-js/dist/styles.css";
const : = ({ }) => {
return new (
[
new ("userId", , 5, {
: "search",
: true,
: true,
}),
new ("userId", , 5, {
: "search-brands",
: true,
}),
],
{
: true,
},
);
};
({
: "#widget-root",
: ,
: ,
: 3,
: 0,
: "(min-width: 1000px)",
: "lg:w-[var(--qs-input-width)] lg:flex lg:justify-center",
: () =>
`<form className="flex w-[400px] text-[#374040]">
<${}
state=${.}
inputProps=${{
: `Search for "table"...`,
}}
/>
</form>`,
: () =>
`<button
...${..}
className="flex size-[38px] items-center justify-center rounded-sm bg-[#3bc4a1] text-white"
>
<${} />
</button>`,
: () =>
`<div
className="mt-1 flex h-full max-h-full min-h-0 flex-col rounded-sm bg-white text-[#374040] shadow-2xl lg:h-auto lg:max-w-[900px] lg:min-w-[600px]"
>
${!.. &&
`<form className="flex items-center gap-2 p-2">
<div className="flex-grow">
<${}
state=${.}
inputProps=${{
: `Search for "table"...`,
}}
/>
</div>
<button
...${..}
className="flex size-[38px] items-center justify-center"
>
<${} />
</button>
</form>`}
<div className="flex">
<div className="flex min-h-0 flex-col">
<div className="px-4 py-4 pb-2 text-sm font-semibold text-[#3f91ff]">
Segments
</div>
<div className="overflow-auto p-2">
${..(1).(
() =>
`<a
key=${.}
href=${(
`${.?.}`,
.,
)}
...${.}
className="flex items-center gap-2 rounded-sm p-2 text-nowrap outline-hidden hover:bg-[#f7f7f7] focus:bg-[#f7f7f7]"
><div className="flex-grow">
<div className="font-semibold">${.}</div>
</div></a
>`,
)}
</div>
</div>
<div className="flex min-h-0 min-w-0 flex-grow flex-col">
<div className="px-4 py-4 pb-2 text-sm font-semibold text-[#3f91ff]">
Results
</div>
<div className="overflow-y-auto p-2">
${.
.(0)
.(
() =>
`<${}
key=${.}
href=${(
`${.?.}`,
.,
)}
image=${`<${}
className="size-16 overflow-hidden rounded-lg"
src=${`${.?.}`}
width=${600}
height=${400}
/>`}
primaryContent=${.?.}
secondaryContent=${.?.}
highlightedContent=${`USD ${.?.}`}
...${.}
/>`,
)}
</div>
</div>
</div>
</div>`,
});
API Reference
QuickSearchWidget
Quick Search widget
QuickSearchWidgetOptions
Quick Search widget options
Properties
container
CSS Selector to target the element where the widget should be inserted.
createRequest
Request factory function. See Quick Example or visit API Reference for overview of available requests.
onRecommResponse
Callback function allowing to intercept and inspect recommendation request+response made by widget.
import React from "react";
import { } from "@recombee/carousel-widget-js";
({
// ...ommited code...
: ({ , }) => {
// use data from request and response for any purpose, i.e. internal tracking
},
});
initialQuery
String to be prefilled into the search input
minSearchCharactersCount
Minimum length of search query for search request to be sent.
typingDebounceDuration
Maximum duration between keystrokes in milliseconds before search request is made.
primaryResultsIndex
Index of request in a batch from which the results are considered to be navigable by arrow keys.
InputComponent
Component responsible for rendering the widget input.
TriggerComponent
Component responsible for rendering the widget trigger on mobile devices.
DropdownComponent
Component responsible for rendering the widget dropdown.
popoverClassNameDisableDefault
Disables default classes of popover wrapper element.
There are some default class names with essential styles applied to the popover wrapper element. This setting disables them as an escape hatch for customization. See Custom CSS.
desktopMediaQuery
CSS media query specifing when the widget should behave as displayed on desktop. By default, widget behaves as mobile-first, filling entire device screen with results dropdown.
QuickSearchWidgetProps
Quick Search component configuration options
Properties
createRequest
Request factory function. See Quick Example or visit API Reference for overview of available requests.
onRecommResponse
Callback function allowing to intercept and inspect recommendation request+response made by widget.
import React from "react";
import { } from "@recombee/carousel-widget-js";
({
// ...ommited code...
: ({ , }) => {
// use data from request and response for any purpose, i.e. internal tracking
},
});
initialQuery
String to be prefilled into the search input
minSearchCharactersCount
Minimum length of search query for search request to be sent.
typingDebounceDuration
Maximum duration between keystrokes in milliseconds before search request is made.
primaryResultsIndex
Index of request in a batch from which the results are considered to be navigable by arrow keys.
InputComponent
Component responsible for rendering the widget input.
TriggerComponent
Component responsible for rendering the widget trigger on mobile devices.
DropdownComponent
Component responsible for rendering the widget dropdown.
popoverClassNameDisableDefault
Disables default classes of popover wrapper element.
There are some default class names with essential styles applied to the popover wrapper element. This setting disables them as an escape hatch for customization. See Custom CSS.
desktopMediaQuery
CSS media query specifing when the widget should behave as displayed on desktop. By default, widget behaves as mobile-first, filling entire device screen with results dropdown.
QuickSearchWidgetState
Class exposing quick search widget state for use in custom templates
Properties
isDesktop
Indicates that the widget is displayed on desktop device.
reset
Resets the widget to its initial state
inputProps
Properties to be passed to a input component.
triggerProps
Properties to be passed to the trigger button of a mobile widget.
closeButtonProps
Properties to be passed to the close button of a mobile dropdown.
items
Getter for current results of the request batch. The index
parameter
indicates an index of results in the Batch Request for which to return
items.
isExpanded
Boolean flag indicating that the widget dropdown is open.
isLoading
Boolean flag indicating that a request for new results is in flight.
ItemImage
Item image component
ItemImageProps
Item Image properties
Properties
src
Image URL
missingImageSrc
URL of an image to display when the main image could not be loaded.
className
Image wrapper class name
imgClassName
Image class name
width
Image width in pixels
height
Image height in pixels
verticalAlignment
Image vertical alignment
horizontalAlignment
Image horizontal alignment
fittingAlgorithm
Image fitting algorithm
addRecommIdQueryParam
Utility function to append recombee_recomm_id
parameter to an url string.
For usage in widget template to construct item link URL.