Select
Trigger + chevron, a floating panel of options, check-marked selection.
A bordered trigger showing the current choice; clicking it opens a floating
panel over the content beneath — built on the shared portal primitive (Floating),
so it escapes any parent clipping, paints above everything, and wins the pointer. Picking an
option, pressing anywhere else, or Escape closes it; the panel opens aligned to the current
selection. Web-specific composition (SelectTrigger/SelectValue
sub-components) and RTL are "from the web": Go structs replace composition, and RTL layout is
not yet supported by the underlying toolkit.
Installation
Use the module import (the default), or own the source: lotusui add
vendors the component into your app and lotusui update keeps the copy mergeable —
see Registry.
go get github.com/ikaito-com/lotusui
# or vendor the source into your app:
go run github.com/ikaito-com/lotusui/cmd/lotusui add select
Usage
Start with Selected: -1 and a Placeholder — the
trigger shows it in muted ink until the user picks. Open the demo's panel: it floats over
whatever is beneath.
fruit := lotusui.Select{
Options: []string{"Apple", "Banana", "Blueberry", "Grapes", "Pineapple"},
Selected: -1,
Placeholder: "Select a fruit",
}
fruit.Layout(th, gtx, "Fruit")
Align item with trigger
AlignItemWithTrigger overlays the open panel so the SELECTED row
sits directly over the trigger — the native-select feel — instead of dropping below. Long
lists still scroll; the alignment accounts for scrolled-away rows.
font := lotusui.Select{Options: fonts, Selected: 3, AlignItemWithTrigger: true}
Groups
Groups renders options under muted labels with separators between
groups. Selected indexes the flattened option list, in order.
produce := lotusui.Select{
Groups: []lotusui.SelectGroup{
{Label: "Fruits", Options: []string{"Apple", "Banana", "Cherry"}},
{Label: "Vegetables", Options: []string{"Carrot", "Leek", "Spinach"}},
},
Selected: -1, Placeholder: "Pick a produce…",
}
Scrollable
The panel caps at seven rows; longer lists scroll inside it, and the panel opens scrolled to the current selection — the align-with-trigger behavior, transposed.
tz := lotusui.Select{Options: timezones, Selected: 10}
Disabled
Freezes the control on its current choice — identity fields that cannot change after creation.
engine.Disabled = true
Invalid
Danger chrome on the trigger — pair it with a Field error message.
size.Invalid = true
Sizes
All seven shared Size presets on the trigger frame.
sel.Size = lotusui.Size2XS // … through lotusui.Size2XL
API
| Option | Type | Description |
|---|---|---|
Options | []string | The choices, rendered as check-markable rows in the floating panel. |
Groups | []SelectGroup | Wins over Options: options under muted labels, separators between groups; Selected indexes the flattened list. |
Size | Size | The shared size presets for the trigger frame. |
Selected | int | Index of the current choice; -1 = nothing chosen yet (shows Placeholder). |
Placeholder | string | Shown in muted ink while Selected is out of range. |
AlignItemWithTrigger | bool | Open the panel with the selected row over the trigger. |
Invalid | bool | Danger chrome on the trigger. |
Disabled | bool | Freezes the control: no pointer cursor, no opening, dimmed value. |