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
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
empty<turbo-frame id="example_empty"> <form id="form_id_empty" action="#" accept-charset="UTF-8" method="get"> <div id="looposui-inputs-select_user_id_5793709857" class="grow" data-controller="input-select" data-input-select-input-outlet="#looposui-inputs-select_user_id_5793709857 .lui-inner-input" data-input-select-mode-value="inline" data-input-select-variant-value="list"> <div class="lui-input-select lui-input-select--inline relative lui-inputs__select lui-input-select--list"> <div data-controller="input" data-input-open-actions-value="false" class="lui-inner-input relative flex gap-2" data-input-original-input-value="" data-input-mode-value="inline" data-input-form-value=""> <div class="w-full flex flex-col"> <div class="lui-input-chrome relative w-full"> <span class="lui-input "> <input name="user_id" type="text" placeholder="Selecione um user" class="lui-input__input" mode="inline" contentEditable="true" data-input-target="input" data-action="input->input#onChange change->input#onChange" data-input-select-target="textInput" readonly="readonly"> <span class="lui-input__addon-right"> <span class="flex flex-row items-center gap-2"> <i class="opacity-0 fa-solid fa-xmark cursor-pointer text-gray-400 lui-input-select__clear hidden!" data-input-select-target="clearButton" data-action="click->input-select#clear"> </i> <div data-input-select-target="icon"> <div class="lui-icon h-[12px] w-[12px]"> <i class="fa-regular fa-chevron-down lui-icon__icon" style="font-size: 12px; color: #212529;"></i> </div> </div> </span> </span> <span class="lui-input__spinner"> <i class="fa-regular fa-spinner"></i> </span> </span> </div> </div> <span class="lui-inner-input__actions opacity-0 flex items-center gap-1 h-fit" data-input-target="actions"> <span class="lui-button__tooltip-wrapper inline-flex w-fit"> <button class="lui-button lui-button--icon-only lui-button--neutral--secondary lui-button--size-tiny w-fit w-fit relative" data-controller="lui--button" data-input-target="cancel" data-action="click->input#handleClose" type="button" disabled="disabled"> <div class="opacity-100 inline-flex" data-lui--button-target="leadingIcon"> <div class="flex items-center justify-center" style="width: 12px; height: 12px;"><i class="lui-button__icon lui-button__icon--tiny fa-regular fa-xmark" data-lui--button-target="leadingIcon"></i></div> </div> <div class="absolute w-full flex items-center justify-center opacity-0" data-lui--button-target="loadingIcon"> <i class="lui-m_icon animate-spin material-symbols-rounded" style="--lui-micon-size: 12px;"> progress_activity </i> </div> </button></span> <span class="lui-button__tooltip-wrapper inline-flex w-fit"> <button class="lui-button lui-button--icon-only lui-button--neutral--secondary lui-button--size-tiny w-fit w-fit relative" data-controller="lui--button" data-input-target="submit" data-action="click->input#setLoading lui--button#startLoading" type="submit" disabled="disabled"> <div class="opacity-100 inline-flex" data-lui--button-target="leadingIcon"> <div class="flex items-center justify-center" style="width: 12px; height: 12px;"><i class="lui-button__icon lui-button__icon--tiny fa-regular fa-check" data-lui--button-target="leadingIcon"></i></div> </div> <div class="absolute w-full flex items-center justify-center opacity-0" data-lui--button-target="loadingIcon"> <i class="lui-m_icon animate-spin material-symbols-rounded" style="--lui-micon-size: 12px;"> progress_activity </i> </div> </button></span> </span> </div> <div data-input-select-target="menu" class="lui-input-select__wrapper"> <div class="lui-input-select__options" role="listbox"> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 1" data-value="1"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 1</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 2" data-value="2"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 2</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> </div> </div> </div> <input type="hidden" name="user_id" id="user_id" data-input-select-target="hiddenInput" /> </div> </form></turbo-frame>pre_selected<turbo-frame id="example_pre_selected"> <form id="form_id_pre_selected" action="#" accept-charset="UTF-8" method="get"> <div id="looposui-inputs-select_user_id_9912568611" class="grow" data-controller="input-select" data-input-select-input-outlet="#looposui-inputs-select_user_id_9912568611 .lui-inner-input" data-input-select-mode-value="inline" data-input-select-variant-value="list"> <div class="lui-input-select lui-input-select--inline relative lui-inputs__select lui-input-select--list"> <div data-controller="input" data-input-open-actions-value="true" class="lui-inner-input relative flex gap-2" data-input-original-input-value="" data-input-mode-value="inline" data-input-form-value=""> <div class="w-full flex flex-col"> <div class="lui-input-chrome relative w-full"> <span class="lui-input "> <input name="user_id" type="text" placeholder="Selecione um user" class="lui-input__input" mode="inline" contentEditable="true" data-input-target="input" data-action="input->input#onChange change->input#onChange" data-input-select-target="textInput" readonly="readonly"> <span class="lui-input__addon-right"> <span class="flex flex-row items-center gap-2"> <i class="opacity-0 fa-solid fa-xmark cursor-pointer text-gray-400 lui-input-select__clear hidden!" data-input-select-target="clearButton" data-action="click->input-select#clear"> </i> <div data-input-select-target="icon"> <div class="lui-icon h-[12px] w-[12px]"> <i class="fa-regular fa-chevron-down lui-icon__icon" style="font-size: 12px; color: #212529;"></i> </div> </div> </span> </span> <span class="lui-input__spinner"> <i class="fa-regular fa-spinner"></i> </span> </span> </div> </div> <span class="lui-inner-input__actions opacity-0 flex items-center gap-1 h-fit" data-input-target="actions"> <span class="lui-button__tooltip-wrapper inline-flex w-fit"> <button class="lui-button lui-button--icon-only lui-button--neutral--secondary lui-button--size-tiny w-fit w-fit relative" data-controller="lui--button" data-input-target="cancel" data-action="click->input#handleClose" type="button" disabled="disabled"> <div class="opacity-100 inline-flex" data-lui--button-target="leadingIcon"> <div class="flex items-center justify-center" style="width: 12px; height: 12px;"><i class="lui-button__icon lui-button__icon--tiny fa-regular fa-xmark" data-lui--button-target="leadingIcon"></i></div> </div> <div class="absolute w-full flex items-center justify-center opacity-0" data-lui--button-target="loadingIcon"> <i class="lui-m_icon animate-spin material-symbols-rounded" style="--lui-micon-size: 12px;"> progress_activity </i> </div> </button></span> <span class="lui-button__tooltip-wrapper inline-flex w-fit"> <button class="lui-button lui-button--icon-only lui-button--neutral--secondary lui-button--size-tiny w-fit w-fit relative" data-controller="lui--button" data-input-target="submit" data-action="click->input#setLoading lui--button#startLoading" type="submit" disabled="disabled"> <div class="opacity-100 inline-flex" data-lui--button-target="leadingIcon"> <div class="flex items-center justify-center" style="width: 12px; height: 12px;"><i class="lui-button__icon lui-button__icon--tiny fa-regular fa-check" data-lui--button-target="leadingIcon"></i></div> </div> <div class="absolute w-full flex items-center justify-center opacity-0" data-lui--button-target="loadingIcon"> <i class="lui-m_icon animate-spin material-symbols-rounded" style="--lui-micon-size: 12px;"> progress_activity </i> </div> </button></span> </span> </div> <div data-input-select-target="menu" class="lui-input-select__wrapper"> <div class="lui-input-select__options" role="listbox"> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 1" data-value="1"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 1</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 2" data-value="2"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 2</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 3" data-value="3"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 3</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 4" data-value="4"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 4</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 5" data-value="5"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 5</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 6" data-value="6"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 6</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 7" data-value="7"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 7</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 8" data-value="8"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 8</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 9" data-value="9"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 9</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> <div class="lui-input-select__option " role="option" data-input-select-target="option" data-text="user 10" data-value="10"> <div class="lui-input-select__option-wrapper"> <div class="lui-input-select__option-text"> <i class="fa-regular fa-user"></i> <span role="text">user 10</span> </div> <i class="fa-regular fa-check hidden!" data-input-select-target="check"></i> </div> </div> </div> </div> </div> <input type="hidden" name="user_id" id="user_id" data-input-select-target="hiddenInput" /> </div> </form></turbo-frame><script> // Example on how you could capture the selected option from outside the component document.getElementById("form_id_empty").addEventListener("input-select:change", function(event) { event.preventDefault(); event.stopPropagation(); console.log(event); });</script>Inputs::Select
Description
Related components
| Used Components | Components where is Used |
|---|---|
| Label |
Usage rules
- ✅ Do
- ❌ Don't
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
empty<%= turbo_frame_tag "example_empty" do %> <%= form_with url: "#", method: :get, id: "form_id_empty" do %> <%= render LooposUi::Inputs::Select.new( name: "user_id", value: params[:user_id], options: [ { value: 1, text: "user 1", icon: "user" }, { value: 2, text: "user 2", icon: "user" } ], placeholder: "Selecione um user", readonly: params[:readonly] || false, clearable: params[:clearable] || false, help: params[:help].presence, error: params[:error].presence, ) %> <% end %><% end %>pre_selected<%= turbo_frame_tag "example_pre_selected" do %> <%= form_with url: "#", method: :get, id: "form_id_pre_selected" do %> <%= render LooposUi::Inputs::Select.new( name: "user_id", options: [ { value: 1, text: "user 1", icon: "user" }, { value: 2, text: "user 2", icon: "user" }, { value: 3, text: "user 3", icon: "user" }, { value: 4, text: "user 4", icon: "user" }, { value: 5, text: "user 5", icon: "user" }, { value: 6, text: "user 6", icon: "user" }, { value: 7, text: "user 7", icon: "user" }, { value: 8, text: "user 8", icon: "user" }, { value: 9, text: "user 9", icon: "user" }, { value: 10, text: "user 10", icon: "user" } ], value: params[:user_id], placeholder: "Selecione um user", readonly: params[:readonly] || false, clearable: params[:clearable] || false, help: params[:help].presence, error: params[:error].presence, open_actions: true, ) %> <% end %><% end %><script> // Example on how you could capture the selected option from outside the component document.getElementById("form_id_empty").addEventListener("input-select:change", function(event) { event.preventDefault(); event.stopPropagation(); console.log(event); });</script>No notes provided.
| Param | Description | Input |
|---|---|---|
|
Input readonly |
|
|
|
Input clearable |
|
|
|
Helper text below the input |
|
|
|
Validation error message |
|
Inputs::Select
Description
Inputs::Select component is used to render select input fields.
Arguments
Most input components have the following base arguments:
Base Arguments
| Property | Default | Description |
|---|---|---|
model |
nil |
ActiveRecord instance. |
attribute |
nil |
Attribute name of the model. |
name |
nil |
Name of the input field. |
value |
nil |
Pre-selected option. Must have the same value as an exisiting option. |
placeholder |
nil |
Placeholder text. |
error |
nil |
Error message. If model is present, the errors will be extracted for the current attribute |
help |
nil |
Help message. |
appearance |
nil |
Visual modifier. Defaults to mode when omitted. |
readonly |
false |
Renders the selected option text as readonly text. |
custom_readonly |
false |
In readonly mode, renders provided content instead of the plain value. |
open_actions |
false |
Open field in edit mode by default. |
extra_input_attributes |
{} |
Attributes to be added to the input element. |
Select Specific arguments
| Property | Default | Description |
|---|---|---|
options |
nil |
Options for the select field. |
mode |
:inline |
Behavioural mode. Can be :inline, :autosubmit or :form. Controls save/cancel actions and form submission. |
variant |
:list |
Visual variant. :list renders the current dropdown. :grid renders all options as visible buttons. |
include_blank |
false |
Adds a blank option. When a string is passed, it is used as the blank label. In grid mode, blank options are omitted. |
clearable |
true |
Shows the clear button in list mode. |
portal_target |
nil |
CSS selector for the element where the dropdown should be portaled. Falls back to modal containers or document.body. |
form |
nil |
Form id to be submitted when the mode is :autosubmit. Will try to use find closest parent if omitted. |
Options schema
| Property | Description |
|---|---|
value |
Value of the option. |
text |
Label of the option. |
icon |
Icon of the option. Can use the shorthand version fa-regular fa-* will be prepended if missing. |
tooltip |
Optional tooltip text shown next to the option label. |
Modes
mode controls the behavioural integration of the Select within a form:
:inline- On change, cancel/save actions appear. The value is persisted when the user confirms.:autosubmit- On change, the form is submitted immediately. Cancel/save actions are hidden.:form- The value is stored in a hidden input and submitted when the surrounding form is submitted. The developer is responsible for providing the submit button and form.
All modes work with both variant: :list and variant: :grid.
Variants
variant controls the visual presentation of the Select:
:list(default) — The current dropdown behaviour: a readonly text input triggers a Tippy popup with the list of options.:grid— All options are always visible as buttons (LooposUi::Button). The underlying hidden input and form submission contract are identical to thelistvariant.
Slots
No slots available for this component.
⚠️ Important
It's the responsibility of the developer to handle the generation of the form, and handling any
turbo frame updates or form submissions.
The recommendation is to use the form_with helper from Rails, along with a turbo_frame_tag, so only the inline component is updated.