ComboBox
Dynamic suggestions as users type in an input field.
Contents
- Overview
- Installation
- Basic usage
- Configuration Options
- JavaScript API
- Events
- Common Patterns
- License
Overview
The ComboBox component provides an autocomplete input field with dynamic suggestions. It supports both client-side filtering and API-based data fetching, customizable templates, and flexible data rendering options.
Key Features:
- Dynamic autocomplete suggestions
- Client-side and API-based data fetching
- Customizable item templates
- Keyboard navigation support
- Programmatic control via JavaScript API
- Event system for selection tracking
- Accessibility attributes (ARIA) built-in
Installation
To get started, install ComboBox plugin via npm, else you can skip this step if you are already using Preline UI as a package.
npm i @preline/combobox
CSS
Use @source to register the plugin's JavaScript path for Tailwind CSS scanning, then @import the plugin's CSS files into your Tailwind CSS file.
@import "tailwindcss";
/* @preline/combobox */
@source "../node_modules/@preline/combobox/*.js";
@import "./node_modules/@preline/combobox/variants.css";
@import "./node_modules/@preline/combobox/theme.css";
JavaScript
Include the JavaScript that powers the interactive elements near the end of your </body> tag:
<script src="./node_modules/@preline/combobox/index.js"></script>
Manual Initialization
Use the non-auto entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly.
<script type="module">
import HSCombobox from "@preline/combobox/non-auto.mjs";
new HSCombobox(document.querySelector("#combobox"));
</script>
Via Bundler
When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module.
@preline/combobox is the auto-init entry: it scans the DOM and initializes matching elements automatically.
import "@preline/combobox";
@preline/combobox/non-auto is the manual entry: use it when you want explicit control over when initialization happens, either via autoInit() or by creating a specific instance yourself.
import HSCombobox from "@preline/combobox/non-auto";
HSCombobox.autoInit();
// Or initialize a specific element manually
const el = document.querySelector("#combobox");
if (el) new HSCombobox(el);
TypeScript
This package ships with TypeScript type definitions. No additional @types/ package is needed.
Basic usage
The following example demonstrates the minimal HTML structure required for a combobox component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The combobox shows suggestions as the user types.
<div class="inline-flex relative" data-hs-combo-box>
<div class="relative">
<input type="text" role="combobox" aria-expanded="false" value="" data-hs-combo-box-input />
</div>
<div class="absolute z-50" style="display: none;" data-hs-combo-box-output>
<div class="cursor-pointer" tabindex="0" data-hs-combo-box-output-item>
<span data-hs-combo-box-search-text="1" data-hs-combo-box-value>1</span>
</div>
<div class="cursor-pointer" tabindex="1" data-hs-combo-box-output-item>
<span data-hs-combo-box-search-text="2" data-hs-combo-box-value>2</span>
</div>
</div>
</div>
Structure Requirements:
data-hs-combo-box: Required on the container elementdata-hs-combo-box-input: Required on the input elementdata-hs-combo-box-output: Required on the dropdown containerdata-hs-combo-box-output-item: Required on each suggestion itemdata-hs-combo-box-search-text: Required on the searchable text element within each item- Proper ARIA attributes (
role="combobox",aria-expanded)
Initial State:
- Set
aria-expanded="false"on the input initially - Add
style="display: none;"to the output container initially - Output visibility is controlled by the plugin
Configuration Options
Data Options
Data options are specified in the data-hs-combo-box attribute and various data attributes.
| Attribute | Target Element | Type | Default | Description |
|---|---|---|---|---|
data-hs-combo-box |
Container | - | - | Activate a ComboBox by specifying on an element. Should be added to the container. |
:gap |
Inside data-hs-combo-box |
number | 5 |
Determines the indent from the input field to the dropdown list in pixels. |
:viewport |
Inside data-hs-combo-box |
string | HTMLElement | null |
Determines which element will be the parent when calculating the position of the dropdown list. By default it is calculated relative to the document. |
:minSearchLength |
Inside data-hs-combo-box |
number | 0 |
Specifies the minimum number of characters that must be entered before the search function becomes active. |
:apiUrl |
Inside data-hs-combo-box |
string | null | null |
Specifies the API address for fetching suggestions. |
:apiDataPart |
Inside data-hs-combo-box |
string | null | null |
Determines which part of the returned data will be taken as the main data array. If this parameter is empty, then the root is taken as a basis. |
:apiQuery |
Inside data-hs-combo-box |
string | null | null |
Defines request parameters, such as limit. |
:apiSearchQuery |
Inside data-hs-combo-box |
string | null | null |
Defines the name of the search parameter. |
:apiHeaders |
Inside data-hs-combo-box |
string | null | null |
Defines request headers. |
:apiSearchPath |
Inside data-hs-combo-box |
string | null | null |
A string that specifies the endpoint path for the API request, excluding the base URL. Note: apiSearchPath and apiSearchDefaultPath are mutually exclusive with apiSearchQuery. |
:apiSearchDefaultPath |
Inside data-hs-combo-box |
string | null | null |
A string that defines the default API endpoint path to be used when the input field is empty. Note: apiSearchPath and apiSearchDefaultPath are mutually exclusive with apiSearchQuery. |
:outputItemTemplate |
Inside data-hs-combo-box |
string | null | Default template | Defines a template for a single item in a dropdown list. |
:outputEmptyTemplate |
Inside data-hs-combo-box |
string | null | Default template | Defines a template for an empty placeholder. |
:outputLoaderTemplate |
Inside data-hs-combo-box |
string | null | Default template | Defines a template for the loader when loading data. |
:preventAutoPosition |
Inside data-hs-combo-box |
boolean | false |
If true, it disables dropdown auto-positioning. |
:preventClientFiltering |
Inside data-hs-combo-box |
boolean | true (if :apiSearchQuery is not empty) |
If true, it disables client-side filtering. |
:keepOriginalOrder |
Inside data-hs-combo-box |
boolean | false |
If true, it keeps the original order of items. |
:preserveSelectionOnEmpty |
Inside data-hs-combo-box |
boolean | true |
If true, it preserves the selected value when the input is empty. |
data-hs-combo-box-input |
Input element | - | - | Determines which element (input) inside the initialized container will be responsible for entering data. |
data-hs-combo-box-output |
Output container | - | - | Determines which element inside the initialized container will be responsible for data output. |
data-hs-combo-box-toggle |
Toggle element | - | - | Defines an element inside the initialized container that will be responsible for hiding/showing the dropdown list. |
data-hs-combo-box-close |
Close element | - | - | Defines an element inside the initialized container that will be responsible for hiding the dropdown list. |
data-hs-combo-box-open |
Open element | - | - | Defines an element inside the initialized container that will be responsible for showing the dropdown list. |
data-hs-combo-box-output-item |
Item element | - | - | Defines an element inside the initialized container that will be responsible for displaying each individual data element. |
data-hs-combo-box-search-text |
Search text element | - | - | Defines the element within which text will be searched. |
data-hs-combo-box-value |
Value element | - | - | Defines an element whose text will be set as a value when selected. |
data-hs-combo-box-output-item-field |
Item field | string | string[] | - | Defines a data field that will be taken to fill the element with text. |
data-hs-combo-box-output-item-attr |
Item attribute | - | - | Defines the attributes that will be filled with the corresponding data. For example, the src attribute of an image. |
:valueFrom |
Inside data-hs-combo-box-output-item-attr |
string | - | Defines the name of the field from which data will be taken. |
:attr |
Inside data-hs-combo-box-output-item-attr |
string | - | Defines the name of the attribute where the data will be supplied. |
Tailwind Modifiers
| Name | Description |
|---|---|
hs-combo-box-active:* |
A modifier that allows you to set Tailwind classes when ComboBox has been opened. |
hs-combo-box-has-value:* |
A modifier that allows you to set Tailwind classes when ComboBox's input has value. |
hs-combo-box-selected:* |
A modifier that allows you to set Tailwind classes when data-hs-combo-box-output-item has been selected. |
hs-combo-box-tab-active:* |
A modifier that allows you to set Tailwind classes to the active group item (tab) when groupingType is tabs. |
JavaScript API
The HSComboBox object is available in the global window object after the plugin is loaded.
Instance Methods
These methods are called on a combobox instance.
| Method | Parameters | Return Type | Description |
|---|---|---|---|
getCurrentData() |
None | object | object[] |
Returns the data of the selected element as an object. This data must first be assigned as a value to the data parameter data-hs-combo-box-item-stored-data when standard rendering. When rendering via the API, the data is automatically substituted into the data attribute. |
setCurrent() |
None | void |
Sets the current selection based on the input value. |
open(val) |
val: string (optional) |
boolean |
Opens the autosuggestion list. Optionally accepts a value to set in the input. Returns true if opened successfully, false otherwise. |
close(val, data) |
val: string | null (optional)data: object | null (optional) |
boolean |
Closes the autosuggestion list. Optionally accepts a value and data to set. Returns true if closed successfully, false otherwise. |
recalculateDirection() |
None | void |
Forces recalculation of autosuggestion list positions. Useful after window resize or layout changes. |
destroy() |
None | void |
Destroys the combobox instance, removes all generated markup, classes, and event listeners. Use when removing combobox from DOM. |
Static Methods
These methods are called directly on the HSComboBox class.
| Method | Parameters | Return Type | Description |
|---|---|---|---|
HSComboBox.getInstance(target, isInstance) |
target: HTMLElement | string (CSS selector)isInstance: boolean (optional) |
HSComboBox | { id: string | number, element: HSComboBox } | null |
Returns the combobox instance associated with the target. If isInstance is true, returns collection item object { id, element } where element is the HSComboBox instance. If isInstance is false or omitted, returns the HSComboBox instance directly. Returns null if combobox instance is not found. |
HSComboBox.autoInit() |
None | void |
Reinitializes all ComboBoxes on the page. Useful after dynamically adding comboboxes to DOM. |
HSComboBox.close(target) |
target: HTMLElement | string (CSS selector) |
void |
Closes the combobox identified by target. Accepts a DOM element or CSS selector string. |
HSComboBox.closeCurrentlyOpened() |
None | void |
Closes an already open ComboBox. Useful for closing any open combobox before opening a new one. |
Usage Examples
Example 1: Using instance methods (public API)
// Create a new combobox instance
const comboBox = new HSComboBox(document.querySelector('#hs-combo-box'));
const openBtn = document.querySelector('#hs-open-btn');
// Open combobox programmatically
openBtn.addEventListener('click', () => {
comboBox.open();
});
Example 2: Getting instance and using methods (recommended pattern)
// Get the combobox instance
const instance = HSComboBox.getInstance('#hs-combo-box', true);
if (instance) {
const { element } = instance; // element is the HSComboBox instance
const openBtn = document.querySelector('#hs-open-btn');
// Use instance methods
openBtn.addEventListener('click', () => {
element.open();
});
// Get selected data
const selectedData = element.getCurrentData();
console.log('Selected:', selectedData);
// Clean up when removing from DOM
function removeComboBox() {
element.destroy();
}
}
Example 3: Destroying combobox instance
const instance = HSComboBox.getInstance('#hs-combo-box', true);
if (instance) {
const { element } = instance;
const removeBtn = document.querySelector('#hs-remove-btn');
removeBtn.addEventListener('click', () => {
// Clean up before removing from DOM
element.destroy();
// Now safe to remove the element
document.querySelector('#hs-combo-box').remove();
});
}
Events
Combobox instances emit events that can be listened to for selection lifecycle hooks.
| Event Name | When Fired | Callback Parameter | Description |
|---|---|---|---|
on:select |
When an item is selected from the dropdown | object (the selected item data object) |
Fires after the user clicks an option in the combobox dropdown. |
Event Usage Example
// Get combobox instance
const instance = HSCombobox.getInstance('#hs-combobox', true);
if (instance) {
const { element } = instance;
// Listen for item selection
element.on('select', (data) => {
console.log('Selected item:', data);
// Use selected data to update other parts of the UI
});
}
Common Patterns
Pattern 1: API-based ComboBox
Fetch suggestions from an API endpoint.
<div data-hs-combo-box='{
"apiUrl": "https://api.example.com/search",
"apiSearchQuery": "q",
"minSearchLength": 2
}'>
<input data-hs-combo-box-input />
<div data-hs-combo-box-output></div>
</div>
Pattern 2: Programmatic Control
Control combobox from external buttons.
<div id="hs-combo-box-first" data-hs-combo-box>
<input data-hs-combo-box-input />
<div data-hs-combo-box-output></div>
</div>
<button id="hs-open-combo-box">Open</button>
<button id="hs-close-combo-box">Close</button>
<script>
const instance = HSComboBox.getInstance('#hs-combo-box-first', true);
if (instance) {
const { element } = instance;
document.querySelector('#hs-open-combo-box').addEventListener('click', () => {
element.open();
});
document.querySelector('#hs-close-combo-box').addEventListener('click', () => {
element.close();
});
}
</script>
License
Copyright (c) 2024 Htmlstream.
Licensed under the MIT License.