@preline/combobox
v4.2.0
Published
Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.
Readme
ComboBox
Dynamic suggestions as users type in an input field.
Contents
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/comboboxCSS
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) 2026 Preline Labs.
Licensed under the MIT License.
