x
    
    1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!-- Single --><select name="frameworks" id="frameworks" data-controller="combobox"><option value="">Select framework...</option><option value="Ruby on Rails">Ruby on Rails</option>  <option value="Laravel">Laravel</option>  <option value="Next.js">Next.js</option>  <option value="Astro">Astro</option>  <option value="Remix">Remix</option></select><!-- Disabled --><select name="frameworks_disabled" id="frameworks_disabled" data-controller="combobox" disabled="disabled"><option value="">Select framework...</option><option value="Ruby on Rails">Ruby on Rails</option>  <option value="Laravel">Laravel</option>  <option value="Next.js">Next.js</option>  <option value="Astro">Astro</option>  <option value="Remix">Remix</option></select><!-- Disabled Options --><select name="option_disabled" id="option_disabled" data-controller="combobox"><option value="">Select framework...</option><option value="Apple">Apple</option>  <option value="Banana">Banana</option>  <option value="Blueberry">Blueberry</option>  <option value="Grapes">Grapes</option>  <option disabled="disabled" value="Pineaple">Pineaple</option></select><!-- Grouped Options --><select name="cars" id="cars" data-controller="combobox"><option value="">Select brand...</option><optgroup label="American"><option value="Ford">Ford</option>    <option value="Chevrolet">Chevrolet</option>    <option value="Dodge">Dodge</option></optgroup><optgroup label="European"><option value="BMW">BMW</option>    <option value="Mercedes-Benz">Mercedes-Benz</option>    <option value="Volkswagen">Volkswagen</option></optgroup><optgroup label="Asian"><option value="Toyota">Toyota</option>    <option value="Honda">Honda</option>    <option value="Nissan">Nissan</option></optgroup></select>1
2
3
4
5
6
7
8
9
10
11
<%# Single %><%= select_tag :frameworks, framework_options, include_blank: "Select framework...", data: { controller: "combobox" } %><%# Disabled %><%= select_tag :frameworks_disabled, framework_options, include_blank: "Select framework...", data: { controller: "combobox" }, disabled: true %><%# Disabled Options %><%= select_tag :option_disabled, fruit_options_with_disabled_items, include_blank: "Select framework...", data: { controller: "combobox" } %><%# Grouped Options %><%= select_tag :cars, car_brand_options, include_blank: "Select brand...", data: { controller: "combobox" }  %>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
@import url("https://esm.sh/tom-select@2.4.3/dist/css/tom-select.min.css");.ts-control {  align-items: center;  background-color: var(--color-surface);  border: 1px solid var(--color-border);  border-radius: var(--rounded-md);  min-block-size: var(--size-9);  color: var(--color-text);  display: inline-flex;  font-size: var(--text-sm);  line-height: inherit;  padding: var(--size-1_5) var(--size-3);  > input {    color: inherit; font-size: inherit;  }}.ts-dropdown {  background-color: var(--color-surface);  border: 1px solid var(--color-border);  border-radius: var(--rounded-md);  box-shadow: var(--shadow-md);  color: var(--color-text);  font-size: var(--text-sm);  line-height: inherit;  /* Setup transition */  transition-behavior: allow-discrete;  transition-duration: var(--time-150);  transition-property: display, opacity, transform;  /* Exit stage to */  opacity: 0;  transform: var(--scale-95);  /* On stage */  .dropdown-active & {    opacity: 1; transform: var(--scale-100);  }  /* Enter stage from */  @starting-style {    .dropdown-active & {      opacity: 0; transform: var(--scale-95);    }  }  .ts-dropdown-content:not(:has(.optgroup)) {    padding: var(--size-1);  }  .optgroup:not(:first-child) {    border-block-start-width: var(--border);  }  .optgroup {    padding: var(--size-1);  }  .optgroup-header {    background-color: inherit;    color: var(--color-text-subtle);    font-size: var(--text-xs);    padding: var(--size-1_5) var(--size-2);  }  .create {    padding: var(--size-1_5) var(--size-2);  }  .option {    border: 1px solid transparent;    border-radius: var(--rounded-md);    padding: var(--size-1_5) var(--size-2);  }  .active {    background-color: var(--color-border-light);    color: inherit !important;  }  .highlight {    background-color: transparent !important;  }  .spinner {    margin: var(--size-1_5) 0 0;  }  .spinner::after {    border-block-color: var(--color-border-dark);  }}.ts-wrapper.single .ts-control {  background-color: var(--color-surface) !important;  background-image: url("chevron-down-zinc-500.svg") !important;  background-position: center right var(--size-2) !important;  background-repeat: no-repeat !important;  background-size: var(--size-4) auto !important;}.ts-wrapper.multi .ts-control > .item {  background: var(--color-border-light);  border-radius: var(--rounded-md);  color: inherit;  line-height: var(--leading-tight);}.disabled .ts-control {  opacity: var(--opacity-50);}.disabled .ts-control * {  cursor: not-allowed !important;}.invalid .ts-control {  border-color: var(--color-negative);}[data-controller~="combobox"] {  clip: rect(0 0 0 0); position: absolute;}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { Controller } from "@hotwired/stimulus"import { get } from "https://esm.sh/@rails/request.js@0.0.12?standalone"import TomSelect from "https://esm.sh/tom-select@2.4.3/base?standalone"export default class extends Controller {  static values = { url: String, optionCreate: { type: String, default: "Add" }, noResults: { type: String, default: "No results found" } }  initialize() {    this.load = this.load.bind(this)  }  connect() {    if (this.element.nodeName === "INPUT") {      this.tomSelect = new TomSelect(this.element, this.#inputSettings)    } else {      this.tomSelect = new TomSelect(this.element, this.#selectSettings)    }  }  disconnect() {    this.tomSelect.destroy()  }  async load(query, callback) {    const response     = await get(this.urlValue, { responseKind: "json", query: { q: query } })    const jsonResponse = await response.json    callback(jsonResponse)  }  get #inputSettings() {    return { render: this.#render, load: this.#loadSetting, persist: false, createOnBlur: true, create: true }  }  get #selectSettings() {    return { render: this.#render, load: this.#loadSetting }  }  get #render() {    return {      option_create: (data, escape) => {        return `<div class="create">${this.optionCreateValue} <b>${escape(data.input)}</b>...</div>`      },      no_results: () =>  {        return `<div class="no-results">${this.noResultsValue}</div>`      }    }  }  get #loadSetting() {    return this.hasUrlValue && this.load  }}