lotusui the ikaito design language for Gio — desktop, mobile, web
GitHub

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
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

Options carry a Label (what the user reads) and a Value (what your app stores) — SelectOpts builds label-only lists. Call Clear() for the placeholder state; read the choice with Value(), never an index. Open the demo's panel: it floats over whatever is beneath.

Go
fruit := lotusui.Select{
	Options:     lotusui.SelectOpts("Apple", "Banana", "Blueberry", "Grapes", "Pineapple"),
	Placeholder: "Select a fruit",
}
fruit.Clear() // start on the placeholder

fruit.Layout(th, gtx, "Fruit")
chosen := fruit.Value() // "Banana"

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.

Go
font := lotusui.Select{Options: fonts, AlignItemWithTrigger: true}
font.SetValue("Roboto")

Groups

Groups renders options under muted labels with separators between groups. Value() reads the choice whichever group it came from — grouping is presentation, not identity.

Go
produce := lotusui.Select{
	Groups: []lotusui.SelectGroup{
		{Label: "Fruits", Options: lotusui.SelectOpts("Apple", "Banana", "Cherry")},
		{Label: "Vegetables", Options: lotusui.SelectOpts("Carrot", "Leek", "Spinach")},
	},
	Placeholder: "Pick a produce…",
}
produce.Clear()

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.

Go
tz := lotusui.Select{Options: timezones}
tz.SetValue("Europe/Paris") // the panel opens scrolled to it

Meta

SelectOption.Meta is optional secondary text on the far right of an option row (and on the closed trigger) — a count, shortcut, … Empty omits it. The selected check still sits after Meta.

Go
lotusui.Select{Options: []lotusui.SelectOption{
	{Label: "roteland", Value: "r", Meta: "1"},
	{Label: "test", Value: "t", Meta: "2"},
}}

Disabled

Freezes the control on its current choice — identity fields that cannot change after creation.

Go
engine.Disabled = true

Invalid

Danger chrome on the trigger — pair it with a Field error message.

Go
size.Invalid = true

Sizes

All seven shared Size presets on the trigger frame.

Go
sel.Size = lotusui.Size2XS // … through lotusui.Size2XL

API

OptionTypeDescription
Options[]SelectOptionThe choices: Label is what the user reads, Value what your app stores (HTML's <option value>). Empty Value = the Label is the value; SelectOpts("a","b") builds label-only lists.
SelectOption.MetastringOptional secondary text on the far right of the option row and closed trigger. Empty omits it; the selected check still sits after Meta.
Groups[]SelectGroupWins over Options: options under muted labels, separators between groups, flattened in order.
SizeSizeThe shared size presets for the trigger frame.
Value() / SetValue(v)stringRead and write the CHOICE — never an index, so reordering or rewording the options cannot change what stored data means. An unknown SetValue clears the choice.
Clear() / Chosen()Back to the placeholder state; whether anything is chosen. The zero value selects the first option, like a <select> with no selected attribute.
PlaceholderstringShown in muted ink while nothing is chosen.
AlignItemWithTriggerboolOpen the panel with the selected row over the trigger.
InvalidboolDanger chrome on the trigger.
DisabledboolFreezes the control: no pointer cursor, no opening, dimmed value.

Every demo on this site is the real Go component compiled to WebAssembly — one gallery app, one bundle, addressed by URL hash.