Combobox
Autocomplete input with a list of suggestions.
<div id="framework-combobox" class="combobox">
<input type="text" role="combobox" placeholder="Select a framework" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="framework-combobox-listbox" class="w-[240px]" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="framework-combobox-popover" data-popover aria-hidden="true">
<div role="listbox" id="framework-combobox-listbox" aria-orientation="vertical" data-empty="No framework found.">
<div role="option" data-value="Next.js">Next.js</div>
<div role="option" data-value="SvelteKit">SvelteKit</div>
<div role="option" data-value="Nuxt.js">Nuxt.js</div>
<div role="option" data-value="Remix">Remix</div>
<div role="option" data-value="Astro">Astro</div>
</div>
</div>
<input type="hidden" name="framework" value="" />
</div>
Usage
HTML + JavaScript
Step 1: Include the JavaScript files
You can either include the JavaScript file for all the components, or just the one for this component:
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1.0.0/dist/js/basecoat.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1.0.0/dist/js/combobox.min.js" defer></script>
Step 2: Add your combobox HTML
Combobox is input-first. The visible input filters the list; the hidden input stores the submitted value.
<div id="framework-combobox" class="combobox">
<input type="text" role="combobox" placeholder="Select a framework" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="framework-combobox-listbox" class="w-[240px]" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="framework-combobox-popover" data-popover aria-hidden="true">
<div role="listbox" id="framework-combobox-listbox" aria-orientation="vertical" data-empty="No framework found.">
<div role="option" data-value="Next.js">Next.js</div>
<div role="option" data-value="SvelteKit">SvelteKit</div>
<div role="option" data-value="Nuxt.js">Nuxt.js</div>
<div role="option" data-value="Remix">Remix</div>
<div role="option" data-value="Astro">Astro</div>
</div>
</div>
<input type="hidden" name="framework" value="" />
</div>
HTML structure
<div class="combobox">- Root element. Add
data-multiple="true"for multiple selection anddata-auto-highlight="true"to highlight the first match while filtering. <input type="text" role="combobox">- The editable control. It should include
aria-expanded,aria-controls, andaria-autocomplete="list". <div class="combobox-chips">Multiple only- Wraps selected chips and the editable input in multiple mode.
<div data-popover>- The suggestions popup. Use
data-sideanddata-alignlike Popover. <div role="listbox">- The suggestions list. Add
aria-multiselectable="true"in multiple mode anddata-emptyfor the empty message. <div role="option" data-value="...">- Selectable option. Options can contain custom HTML; use
data-labelwhen the visible input should use different text than the rendered content. <input type="hidden">- Submitted value. Single mode stores a string; multiple mode stores a JSON array.
JavaScript events
basecoat:initialized- Dispatched on the component after initialization.
basecoat:popover- Dispatched on
documentwhen the popup opens so other popup components can close. change- Dispatched on selection changes with
event.detail.value.
JavaScript methods
value- Gets or sets the selected value. Multiple mode uses an array.
select(value)- Selects an option by value.
deselect(value)Multiple only- Removes a selected value.
toggle(value)Multiple only- Toggles a selected value.
refresh()- Rescans options after changing children inside the existing
role="listbox"element. window.basecoat.refresh(combobox)- Calls the component refresh method through the global dispatcher.
Jinja and Nunjucks
Use the combobox() macro for Nunjucks or Jinja.
{% call combobox(
placeholder="Select a framework",
listbox_attrs={"data-empty": "No framework found."}
) %}
<div role="option" data-value="nextjs">Next.js</div>
<div role="option" data-value="sveltekit">SvelteKit</div>
<div role="option" data-value="nuxtjs">Nuxt.js</div>
{% endcall %}
Examples
Multiple
<div id="frameworks-combobox" class="combobox" data-multiple="true" data-auto-highlight="true">
<div class="combobox-chips w-[320px]">
<input type="text" role="combobox" placeholder="Add framework" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="frameworks-combobox-listbox" />
</div>
<div id="frameworks-combobox-popover" data-popover aria-hidden="true">
<div role="listbox" id="frameworks-combobox-listbox" aria-orientation="vertical" aria-multiselectable="true" data-empty="No framework found.">
<div role="option" data-value="Next.js">Next.js</div>
<div role="option" data-value="SvelteKit">SvelteKit</div>
<div role="option" data-value="Nuxt.js">Nuxt.js</div>
<div role="option" data-value="Remix">Remix</div>
<div role="option" data-value="Astro">Astro</div>
</div>
</div>
<input type="hidden" name="frameworks" value='["Next.js"]' />
</div>
Groups
<div id="timezone-combobox" class="combobox">
<input type="text" role="combobox" placeholder="Search timezone" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="timezone-combobox-listbox" class="w-[280px]" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="timezone-combobox-popover" data-popover aria-hidden="true">
<div role="listbox" id="timezone-combobox-listbox" aria-orientation="vertical" data-empty="No timezone found.">
<div role="group" aria-labelledby="timezone-americas">
<div role="heading" id="timezone-americas">Americas</div>
<div role="option" data-value="America/New_York">(GMT-5) New York</div>
<div role="option" data-value="America/Los_Angeles">(GMT-8) Los Angeles</div>
<div role="option" data-value="America/Sao_Paulo">(GMT-3) São Paulo</div>
</div>
<hr role="separator" />
<div role="group" aria-labelledby="timezone-europe">
<div role="heading" id="timezone-europe">Europe</div>
<div role="option" data-value="Europe/London">(GMT+0) London</div>
<div role="option" data-value="Europe/Paris">(GMT+1) Paris</div>
<div role="option" data-value="Europe/Berlin">(GMT+1) Berlin</div>
</div>
</div>
</div>
<input type="hidden" value="" />
</div>
Custom Items
<div id="country-combobox" class="combobox">
<input type="text" role="combobox" placeholder="Search countries" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="country-combobox-listbox" class="w-[280px]" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="country-combobox-popover" data-popover aria-hidden="true">
<div role="listbox" id="country-combobox-listbox" aria-orientation="vertical" data-empty="No country found.">
<div role="option" data-value="argentina" data-label="Argentina" data-filter="Argentina South America">
<span class="flex flex-col">
<span>Argentina</span>
<span class="text-muted-foreground text-xs">South America (ar)</span>
</span>
</div>
<div role="option" data-value="japan" data-label="Japan" data-filter="Japan Asia">
<span class="flex flex-col">
<span>Japan</span>
<span class="text-muted-foreground text-xs">Asia (jp)</span>
</span>
</div>
<div role="option" data-value="united-states" data-label="United States" data-filter="United States North America USA">
<span class="flex flex-col">
<span>United States</span>
<span class="text-muted-foreground text-xs">North America (us)</span>
</span>
</div>
</div>
</div>
<input type="hidden" value="" />
</div>
Invalid
Select a framework to continue.
<div role="group" class="field" data-invalid="true">
<label for="invalid-combobox-input">Framework</label>
<div id="invalid-combobox" class="combobox">
<input type="text" role="combobox" placeholder="Select a framework" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="invalid-combobox-listbox" class="w-[240px]" id="invalid-combobox-input" aria-invalid="true" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="invalid-combobox-popover" data-popover aria-hidden="true">
<div role="listbox" id="invalid-combobox-listbox" aria-orientation="vertical" data-empty="No framework found.">
<div role="option" data-value="Next.js">Next.js</div>
<div role="option" data-value="SvelteKit">SvelteKit</div>
<div role="option" data-value="Nuxt.js">Nuxt.js</div>
<div role="option" data-value="Remix">Remix</div>
<div role="option" data-value="Astro">Astro</div>
</div>
</div>
<input type="hidden" value="" />
</div>
<p class="field-error" role="alert">Select a framework to continue.</p>
</div>
Disabled
<div id="combobox-750016" class="combobox">
<input type="text" role="combobox" placeholder="Select a framework" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="combobox-750016-listbox" class="w-[240px]" disabled="disabled" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="combobox-750016-popover" data-popover aria-hidden="true">
<div role="listbox" id="combobox-750016-listbox" aria-orientation="vertical">
<div role="option" data-value="nextjs">Next.js</div>
</div>
</div>
<input type="hidden" value="" />
</div>
Auto Highlight
<div id="combobox-608792" class="combobox" data-auto-highlight="true">
<input type="text" role="combobox" placeholder="Select a framework" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="combobox-608792-listbox" class="w-[240px]" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="combobox-608792-popover" data-popover aria-hidden="true">
<div role="listbox" id="combobox-608792-listbox" aria-orientation="vertical">
<div role="option" data-value="Next.js">Next.js</div>
<div role="option" data-value="SvelteKit">SvelteKit</div>
<div role="option" data-value="Nuxt.js">Nuxt.js</div>
<div role="option" data-value="Remix">Remix</div>
<div role="option" data-value="Astro">Astro</div>
</div>
</div>
<input type="hidden" value="" />
</div>
Top Side
<div id="combobox-864105" class="combobox">
<input type="text" role="combobox" placeholder="Select a framework" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="combobox-864105-listbox" class="w-[240px]" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="combobox-864105-popover" data-popover aria-hidden="true" data-side="top">
<div role="listbox" id="combobox-864105-listbox" aria-orientation="vertical">
<div role="option" data-value="Next.js">Next.js</div>
<div role="option" data-value="SvelteKit">SvelteKit</div>
<div role="option" data-value="Nuxt.js">Nuxt.js</div>
<div role="option" data-value="Remix">Remix</div>
<div role="option" data-value="Astro">Astro</div>
</div>
</div>
<input type="hidden" value="" />
</div>
RTL
<div dir="rtl">
<div id="combobox-897314" class="combobox">
<input type="text" role="combobox" placeholder="اختر إطار عمل" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" aria-expanded="false" aria-controls="combobox-897314-listbox" class="w-[240px]" />
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="combobox-trigger-icon"><path d="m6 9 6 6 6-6" /></svg>
<div id="combobox-897314-popover" data-popover aria-hidden="true">
<div role="listbox" id="combobox-897314-listbox" aria-orientation="vertical">
<div role="option" data-value="nextjs">Next.js</div>
<div role="option" data-value="sveltekit">SvelteKit</div>
<div role="option" data-value="astro">Astro</div>
</div>
</div>
<input type="hidden" value="" />
</div>
</div>