<select class="select w-[180px]">
<optgroup label="Fruits">
<option>Apple</option>
<option>Banana</option>
<option>Blueberry</option>
<option>Grapes</option>
<option>Pineapple</option>
</optgroup>
</select>
Fruits
Apple
Banana
Blueberry
Grapes
Pineapple
<div class="select">
<button type="button" class="btn-outline justify-between font-normal w-[180px]" id="select-851776-trigger" popovertarget="select-851776" aria-haspopup="listbox" aria-expanded="false" aria-controls="select-851776-listbox">
<span class="truncate">Apple</span>
<svg 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="lucide lucide-chevrons-up-down-icon lucide-chevrons-up-down text-muted-foreground opacity-50 shrink-0">
<path d="m7 15 5 5 5-5" />
<path d="m7 9 5-5 5 5" />
</svg>
</button>
<div popover id="select-851776" class="popover">
<header>
<svg 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="lucide lucide-search-icon lucide-search">
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3" />
</svg>
<input type="text" value="" placeholder="Search entries..." autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" role="combobox" aria-expanded="true" aria-controls="select-851776-content" aria-labelledby="select-851776-trigger" />
</header>
<div role="listbox" id="select-851776-listbox" aria-orientation="vertical" aria-labelledby="select-851776-trigger">
<div role="group" aria-labelledby="group-label-select-851776-items-1">
<div role="heading" id="group-label-select-851776-items-1">Fruits</div>
<div id="select-851776-items-1-1" role="option" data-value="apple" aria-selected="true">Apple</div>
<div id="select-851776-items-1-2" role="option" data-value="banana">Banana</div>
<div id="select-851776-items-1-3" role="option" data-value="blueberry">Blueberry</div>
<div id="select-851776-items-1-4" role="option" data-value="pineapple">Grapes</div>
<div id="select-851776-items-1-5" role="option" data-value="pineapple">Pineapple</div>
</div>
</div>
</div>
<input type="hidden" name="select-851776-value" value="" />
</div>
Usage
HTML
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).
<select class="select w-[180px]">
<optgroup label="Fruits">
<option>Apple</option>
<option>Banana</option>
<option>Blueberry</option>
<option>Grapes</option>
<option>Pineapple</option>
</optgroup>
</select>
HTML + JavaScript
Step 1: Include the JavaScript files
Include the select.js
file. It is recommended to also include the CSS anchor positioning polyfill to support older browsers. Add this to the <head>
of your page:
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@beta/dist/js/select.min.js" defer></script>
<script type="module">
if (!("anchorName" in document.documentElement.style)) {
import("https://cdn.jsdelivr.net/npm/basecoat-css@beta/dist/js/css-anchor-positioning.min.js");
}
</script>
Step 2: Add your select HTML
<div class="select">
<button type="button" class="btn-outline justify-between font-normal w-[180px]" id="select-851776-trigger" popovertarget="select-851776" aria-haspopup="listbox" aria-expanded="false" aria-controls="select-851776-listbox">
<span class="truncate">Apple</span>
<svg 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="lucide lucide-chevrons-up-down-icon lucide-chevrons-up-down text-muted-foreground opacity-50 shrink-0">
<path d="m7 15 5 5 5-5" />
<path d="m7 9 5-5 5 5" />
</svg>
</button>
<div popover id="select-851776" class="popover">
<header>
<svg 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="lucide lucide-search-icon lucide-search">
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3" />
</svg>
<input type="text" value="" placeholder="Search entries..." autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" role="combobox" aria-expanded="true" aria-controls="select-851776-content" aria-labelledby="select-851776-trigger" />
</header>
<div role="listbox" id="select-851776-listbox" aria-orientation="vertical" aria-labelledby="select-851776-trigger">
<div role="group" aria-labelledby="group-label-select-851776-items-1">
<div role="heading" id="group-label-select-851776-items-1">Fruits</div>
<div id="select-851776-items-1-1" role="option" data-value="apple" aria-selected="true">Apple</div>
<div id="select-851776-items-1-2" role="option" data-value="banana">Banana</div>
<div id="select-851776-items-1-3" role="option" data-value="blueberry">Blueberry</div>
<div id="select-851776-items-1-4" role="option" data-value="pineapple">Grapes</div>
<div id="select-851776-items-1-5" role="option" data-value="pineapple">Pineapple</div>
</div>
</div>
</div>
<input type="hidden" name="select-851776-value" value="" />
</div>
HTML structure
<div class="select">
- Wraps around the entire component.
<button type="button" popovertarget="{ POPOVER_ID }">
-
The trigger to open the popover, can also have the following attributes:
id="{BUTTON_ID}"
: linked to by thearia-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 }"
: points to the active option's id.
<div popover class="popover" id="{ POPOVER_ID }">
- As with the Popover component, you can set up the side and alignment of the popover using the
data-side
anddata-align
attributes.<div role="listbox">
- The listbox containing the options. Should have the following attributes:
id="{ LISTBOX_ID }"
: refered to by thearia-controls
attribute of the trigger.aria-labelledby="{ BUTTON_ID }"
: linked to by the button'sid
attribute.
<div role="option" data-value="{ VALUE }">
- Option that can be selected.Should have a unique id if you use the
aria-activedescendant
attribute on the trigger. <hr role="separator">
Optional- Separator between groups/options.
<div role="group">
Optional- Group of options, can have a
aria-labelledby
attribute to link to a heading. <span role="heading">
- Group heading, must have an
id
attribute if you use thearia-labelledby
attribute on the group.
<input type="hidden" name="{ NAME }" value="{ VALUE }">
Optional- The hidden input that holds the value of the field (if needed).
Jinja and Nunjucks
You can use the select()
Nunjucks or Jinja macro for this component.
{{ select(
items=[
{
type: "group",
label: "Fruits",
items: [
{ type: "item", value: "apple", label: "Apple" },
{ type: "item", value: "banana", label: "Banana" },
{ type: "item", value: "blueberry", label: "Blueberry" },
{ type: "item", value: "pineapple", label: "Grapes" },
{ type: "item", value: "pineapple", label: "Pineapple" }
]
}
]
) }}
Examples
Scrollable
<div class="select">
<button type="button" class="btn-outline justify-between font-normal" id="select-255812-trigger" popovertarget="select-255812" aria-haspopup="listbox" aria-expanded="false" aria-controls="select-255812-listbox">
<span class="truncate"></span>
<svg 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="lucide lucide-chevron-down-icon lucide-chevron-down text-muted-foreground opacity-50 shrink-0"><path d="m6 9 6 6 6-6" /></svg>
</button>
<div popover id="select-255812" class="popover">
<div role="listbox" id="select-255812-listbox" aria-orientation="vertical" aria-labelledby="select-255812-trigger" class="scrollbar overflow-y-auto max-h-64">
<div role="option" data-value="item-0">Item 0</div>
<div role="option" data-value="item-1">Item 1</div>
<div role="option" data-value="item-2">Item 2</div>
<div role="option" data-value="item-3">Item 3</div>
<div role="option" data-value="item-4">Item 4</div>
<div role="option" data-value="item-5">Item 5</div>
<div role="option" data-value="item-6">Item 6</div>
<div role="option" data-value="item-7">Item 7</div>
<div role="option" data-value="item-8">Item 8</div>
<div role="option" data-value="item-9">Item 9</div>
<div role="option" data-value="item-10">Item 10</div>
<div role="option" data-value="item-11">Item 11</div>
<div role="option" data-value="item-12">Item 12</div>
<div role="option" data-value="item-13">Item 13</div>
<div role="option" data-value="item-14">Item 14</div>
<div role="option" data-value="item-15">Item 15</div>
<div role="option" data-value="item-16">Item 16</div>
<div role="option" data-value="item-17">Item 17</div>
<div role="option" data-value="item-18">Item 18</div>
<div role="option" data-value="item-19">Item 19</div>
<div role="option" data-value="item-20">Item 20</div>
<div role="option" data-value="item-21">Item 21</div>
<div role="option" data-value="item-22">Item 22</div>
<div role="option" data-value="item-23">Item 23</div>
<div role="option" data-value="item-24">Item 24</div>
<div role="option" data-value="item-25">Item 25</div>
<div role="option" data-value="item-26">Item 26</div>
<div role="option" data-value="item-27">Item 27</div>
<div role="option" data-value="item-28">Item 28</div>
<div role="option" data-value="item-29">Item 29</div>
<div role="option" data-value="item-30">Item 30</div>
<div role="option" data-value="item-31">Item 31</div>
<div role="option" data-value="item-32">Item 32</div>
<div role="option" data-value="item-33">Item 33</div>
<div role="option" data-value="item-34">Item 34</div>
<div role="option" data-value="item-35">Item 35</div>
<div role="option" data-value="item-36">Item 36</div>
<div role="option" data-value="item-37">Item 37</div>
<div role="option" data-value="item-38">Item 38</div>
<div role="option" data-value="item-39">Item 39</div>
<div role="option" data-value="item-40">Item 40</div>
<div role="option" data-value="item-41">Item 41</div>
<div role="option" data-value="item-42">Item 42</div>
<div role="option" data-value="item-43">Item 43</div>
<div role="option" data-value="item-44">Item 44</div>
<div role="option" data-value="item-45">Item 45</div>
<div role="option" data-value="item-46">Item 46</div>
<div role="option" data-value="item-47">Item 47</div>
<div role="option" data-value="item-48">Item 48</div>
<div role="option" data-value="item-49">Item 49</div>
<div role="option" data-value="item-50">Item 50</div>
<div role="option" data-value="item-51">Item 51</div>
<div role="option" data-value="item-52">Item 52</div>
<div role="option" data-value="item-53">Item 53</div>
<div role="option" data-value="item-54">Item 54</div>
<div role="option" data-value="item-55">Item 55</div>
<div role="option" data-value="item-56">Item 56</div>
<div role="option" data-value="item-57">Item 57</div>
<div role="option" data-value="item-58">Item 58</div>
<div role="option" data-value="item-59">Item 59</div>
<div role="option" data-value="item-60">Item 60</div>
<div role="option" data-value="item-61">Item 61</div>
<div role="option" data-value="item-62">Item 62</div>
<div role="option" data-value="item-63">Item 63</div>
<div role="option" data-value="item-64">Item 64</div>
<div role="option" data-value="item-65">Item 65</div>
<div role="option" data-value="item-66">Item 66</div>
<div role="option" data-value="item-67">Item 67</div>
<div role="option" data-value="item-68">Item 68</div>
<div role="option" data-value="item-69">Item 69</div>
<div role="option" data-value="item-70">Item 70</div>
<div role="option" data-value="item-71">Item 71</div>
<div role="option" data-value="item-72">Item 72</div>
<div role="option" data-value="item-73">Item 73</div>
<div role="option" data-value="item-74">Item 74</div>
<div role="option" data-value="item-75">Item 75</div>
<div role="option" data-value="item-76">Item 76</div>
<div role="option" data-value="item-77">Item 77</div>
<div role="option" data-value="item-78">Item 78</div>
<div role="option" data-value="item-79">Item 79</div>
<div role="option" data-value="item-80">Item 80</div>
<div role="option" data-value="item-81">Item 81</div>
<div role="option" data-value="item-82">Item 82</div>
<div role="option" data-value="item-83">Item 83</div>
<div role="option" data-value="item-84">Item 84</div>
<div role="option" data-value="item-85">Item 85</div>
<div role="option" data-value="item-86">Item 86</div>
<div role="option" data-value="item-87">Item 87</div>
<div role="option" data-value="item-88">Item 88</div>
<div role="option" data-value="item-89">Item 89</div>
<div role="option" data-value="item-90">Item 90</div>
<div role="option" data-value="item-91">Item 91</div>
<div role="option" data-value="item-92">Item 92</div>
<div role="option" data-value="item-93">Item 93</div>
<div role="option" data-value="item-94">Item 94</div>
<div role="option" data-value="item-95">Item 95</div>
<div role="option" data-value="item-96">Item 96</div>
<div role="option" data-value="item-97">Item 97</div>
<div role="option" data-value="item-98">Item 98</div>
</div>
</div>
<input type="hidden" name="select-255812-value" value="" />
</div>
Disabled
Disabled
<div class="select">
<button type="button" class="btn-outline justify-between font-normal" id="select-329343-trigger" popovertarget="select-329343" aria-haspopup="listbox" aria-expanded="false" aria-controls="select-329343-listbox" disabled="disabled">
<span class="truncate"></span>
<svg 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="lucide lucide-chevron-down-icon lucide-chevron-down text-muted-foreground opacity-50 shrink-0"><path d="m6 9 6 6 6-6" /></svg>
</button>
<div popover id="select-329343" class="popover">
<div role="listbox" id="select-329343-listbox" aria-orientation="vertical" aria-labelledby="select-329343-trigger">
<div role="option" data-value="disabled">Disabled</div>
</div>
</div>
<input type="hidden" name="select-329343-value" value="" />
</div>
With icon
Bar
Line
Pie
<div class="select">
<button type="button" class="btn-outline justify-between font-normal w-[180px]" id="select-157814-trigger" popovertarget="select-157814" aria-haspopup="listbox" aria-expanded="false" aria-controls="select-157814-listbox">
<span class="truncate"></span>
<svg 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="lucide lucide-chevron-down-icon lucide-chevron-down text-muted-foreground opacity-50 shrink-0"><path d="m6 9 6 6 6-6" /></svg>
</button>
<div popover id="select-157814" class="popover">
<div role="listbox" id="select-157814-listbox" aria-orientation="vertical" aria-labelledby="select-157814-trigger">
<div type="button" role="option" data-value="bar">
<span class="flex items-center gap-2">
<svg 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="text-muted-foreground">
<path d="M3 3v16a2 2 0 0 0 2 2h16" />
<path d="M7 16h8" />
<path d="M7 11h12" />
<path d="M7 6h3" />
</svg>
Bar
</span>
</div>
<div type="button" role="option" data-value="line">
<span class="flex items-center gap-2">
<svg 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="text-muted-foreground">
<path d="M3 3v16a2 2 0 0 0 2 2h16" />
<path d="m19 9-5 5-4-4-3 3" />
</svg>
Line
</span>
</div>
<div type="button" role="option" data-value="pie">
<span class="flex items-center gap-2">
<svg 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="text-muted-foreground">
<path d="M21 12c.552 0 1.005-.449.95-.998a10 10 0 0 0-8.953-8.951c-.55-.055-.998.398-.998.95v8a1 1 0 0 0 1 1z" />
<path d="M21.21 15.89A10 10 0 1 1 8 2.83" />
</svg>
Pie
</span>
</div>
</div>
</div>
<input type="hidden" name="select-157814-value" value="" />
</div>