--- layout: layouts/page.njk title: Select description: Displays a list of options for the user to pick from—triggered by a button. toc: - label: Usage id: usage children: - label: HTML id: usage-html - label: HTML + JavaScript id: usage-html-js children: - label: "Step 1: Include the JavaScript files" id: usage-html-js-1 - label: "Step 2: Add your select HTML" id: usage-html-js-2 - label: HTML structure id: usage-html-js-3 - label: JavaScript events id: usage-html-js-4 - label: JavaScript methods id: usage-html-js-5 - label: Jinja and Nunjucks id: usage-macro - label: Examples id: examples children: - label: Scrollable id: example-scrollable - label: Disabled id: example-disabled - label: With icon id: example-with-icon - label: Multiple id: example-multiple --- {% from "macros/code_preview.njk" import code_preview %} {% from "macros/code_block.njk" import code_block %} {% from "select.njk" import select %} {% set code_native %}{% endset %} {{ code_preview("select-native", code_native) }} {% set code_html %} {{ select( trigger_attrs={"class": "w-[180px]"}, is_combobox=true, multiple=true, items=[ { type: "group", label: "Fruits", items: [ { type: "item", label: "Apple", attrs: {"data-force": "true"} }, { type: "item", label: "Banana", attrs: {"data-keywords": "bread"} }, { type: "item", label: "Blueberry" }, { type: "item", value: "pineapple", label: "Grapes" }, { type: "item", value: "pineapple", label: "Pineapple" } ] } ] ) }} {% endset %} {% set code_script %} {% endset %} {{ code_preview("select", code_script | prettyHtml ~ code_html | prettyHtml) }}
If you use a <select> element, just add the select class to it or have a parent with the form class (read more about form).
You can either include the JavaScript file for all the components, or just the one for this component by adding this to the <head> of your page:
<div class="select">Wraps around the entire component. Can have the following attributes:
data-placeholder="{ TEXT }" Optional: placeholder text shown when no options are selected (multiselect only).<button type="button">The trigger to open the popover. Should have the following attributes:
id="{BUTTON_ID}": linked to by the aria-labelledby attribute of the listbox.aria-haspopup="listbox": indicates that the button opens a listbox.aria-controls="{ LISTBOX_ID }": points to the listbox's id.aria-expanded="false": tracks the popover's state.aria-activedescendant="{ OPTION_ID }" Optional: points to the active option's id.<div data-popover aria-hidden="true" id="{ POPOVER_ID }">data-side and data-align attributes (see Popover component).
<div role="listbox">The listbox containing the options. Should have the following attributes:
id="{ LISTBOX_ID }": refered to by the aria-controls attribute of the trigger.aria-labelledby="{ BUTTON_ID }": linked to by the button's id attribute.aria-multiselectable="true" Optional: enables multiple selection mode.<div role="option" data-value="{ VALUE }">Option that can be selected. Should have the following attributes:
id="{ OPTION_ID }" Optional: unique id for this option (needed if you use aria-activedescendant on the trigger).data-value="{ VALUE }": the value for this option.data-label="{ LABEL }" Optional: the text label to use for this option when selected in multiple mode. If not provided, the option's text content will be used (HTML stripped).aria-selected="true" Optional: indicates this option is selected.<hr role="separator"> Optional<div role="group"> Optionalaria-labelledby attribute to link to a heading.<span role="heading"> Optionalid attribute if you use the aria-labelledby attribute on the group.<input type="hidden" name="{ NAME }" value="{ VALUE }">The hidden input that holds the selected value.
For single-select: contains the selected option's value as a string.
For multiselect: contains a JSON array of selected values (e.g., ["apple","banana"]). When no options are selected, contains an empty array ([]).
Backend handling: Parse the JSON value on the server side. For example:
values = json.loads(request.form.get('field', '[]'))$values = json_decode($_POST['field'] ?? '[]', true);const values = JSON.parse(req.body.field || '[]');values = JSON.parse(params[:field] || '[]')basecoat:initializedbasecoat:initialized event on itself.basecoat:popoverbasecoat:popover event on document. Other popover components (Combobox, Dropdown Menu, Popover and Select) listen for this to close any open popovers.changeWhen the selected value changes, the component dispatches a custom (bubbling) change event on itself, with the selected value in event.detail.value:
{ detail: { value: "something" }} (string){ detail: { value: ["item1", "item2"] }} (array)value (property)Get or set the current value. For single-select, this is a string. For multiselect, this is an array. The multiselect setter accepts both strings and arrays.
{% set code_value %}{% endset %} {{ code_block(code_value | prettyHtml, "html") }}select(value)Selects an option by value (i.e. the option with the matching data-value attribute). For single-select, this will close the popover. For multiselect, this adds the value to the selection if not already selected.
deselect(value) Multiselect onlyRemoves a specific value from the selection. Only available when the component is in multiselect mode (aria-multiselectable="true").
toggle(value) Multiselect onlyToggles a specific value in the selection (adds if not present, removes if present). Only available when the component is in multiselect mode (aria-multiselectable="true").
selectAll() Multiselect onlySelects all available options. Only available when the component is in multiselect mode (aria-multiselectable="true").
selectNone() Multiselect onlyDeselects all options. Only available when the component is in multiselect mode (aria-multiselectable="true").
selectByValue(value)Deprecated: Alias for select(value). Kept for backward compatibility.
You can use the select() Nunjucks or Jinja macro for this component.
Enable multiple selection by setting adding aria-multiselectable="true" to the listbox. The selected options are displayed as a comma-separated list in the trigger button. Use data-label to specify clean text labels for options that contain HTML (like icons), otherwise the text content will be extracted automatically.