Documentation
¶
Overview ¶
Package tui provides reusable terminal UI components built on top of Bubbletea v2 and Bubbles v2. All components use pointer receivers so they can be stored as the Field interface in a Screen without extra copying.
Index ¶
- Constants
- Variables
- func RunConfirm(title, description string) bool
- type ConfirmField
- func (f *ConfirmField) Blur()
- func (f *ConfirmField) Focus() tea.Cmd
- func (f *ConfirmField) Focusable() bool
- func (f *ConfirmField) Update(msg tea.Msg) (Field, tea.Cmd)
- func (f *ConfirmField) Validate() error
- func (f *ConfirmField) Value() bool
- func (f *ConfirmField) View(focused bool, width int) string
- type Field
- type Keys
- type MultiSelectField
- func (f *MultiSelectField) Blur()
- func (f *MultiSelectField) Focus() tea.Cmd
- func (f *MultiSelectField) Focusable() bool
- func (f *MultiSelectField) Update(msg tea.Msg) (Field, tea.Cmd)
- func (f *MultiSelectField) Validate() error
- func (f *MultiSelectField) View(focused bool, width int) string
- func (f *MultiSelectField) WithItemSelected(value string, sel bool) *MultiSelectField
- func (f *MultiSelectField) WithReadOnly() *MultiSelectField
- func (f *MultiSelectField) WithSelected(values []string) *MultiSelectField
- func (f *MultiSelectField) WithValidate(fn func([]string) error) *MultiSelectField
- type NoteField
- type Option
- type Screen
- type SelectField
- type TextField
- func (f *TextField) Blur()
- func (f *TextField) Focus() tea.Cmd
- func (f *TextField) Focusable() bool
- func (f *TextField) SetError(msg string)
- func (f *TextField) Update(msg tea.Msg) (Field, tea.Cmd)
- func (f *TextField) Validate() error
- func (f *TextField) Value() string
- func (f *TextField) View(focused bool, width int) string
- func (f *TextField) WithMask() *TextField
- func (f *TextField) WithPlaceholder(p string) *TextField
- func (f *TextField) WithValidate(fn func(string) error) *TextField
Constants ¶
const ( GlyphCursor = "❯" GlyphCheck = "✓" GlyphCross = "✗" GlyphBullet = "•" )
Glyph constants used across all field renders.
Variables ¶
var ( ColorFocus = lipgloss.Color("63") // indigo – focused borders / cursors ColorAccent = lipgloss.Color("215") // amber – titles / highlights ColorMuted = lipgloss.Color("241") // grey – descriptions / footer ColorError = lipgloss.Color("196") // red – validation errors ColorSuccess = lipgloss.Color("46") // green – success marks ColorText = lipgloss.Color("252") // off-white – body text ColorBright = lipgloss.Color("255") // white – selected / important text ColorDim = lipgloss.Color("240") // dark grey – unfocused options )
Palette — all colours used across GDG TUIs in one place.
var ( TitleStyle = lipgloss.NewStyle().Bold(true).Foreground(ColorBright) DescStyle = lipgloss.NewStyle().Foreground(ColorMuted) ErrorStyle = lipgloss.NewStyle().Foreground(ColorError) FocusStyle = lipgloss.NewStyle().Foreground(ColorFocus) BlurStyle = lipgloss.NewStyle().Foreground(ColorDim) AccentStyle = lipgloss.NewStyle().Foreground(ColorAccent) SuccessStyle = lipgloss.NewStyle().Foreground(ColorSuccess) )
Shared text styles.
var DefaultKeys = Keys{ Up: key.NewBinding(key.WithKeys("up", "k"), key.WithHelp("↑/k", "up")), Down: key.NewBinding(key.WithKeys("down", "j"), key.WithHelp("↓/j", "down")), Tab: key.NewBinding(key.WithKeys("tab"), key.WithHelp("tab", "next field")), ShiftTab: key.NewBinding(key.WithKeys("shift+tab"), key.WithHelp("shift+tab", "prev field")), Enter: key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "confirm")), Space: key.NewBinding(key.WithKeys(" ", "space"), key.WithHelp("space", "toggle")), Esc: key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "back")), Quit: key.NewBinding(key.WithKeys("ctrl+c"), key.WithHelp("ctrl+c", "quit")), }
DefaultKeys is the standard key map shared by all GDG screens.
Functions ¶
func RunConfirm ¶
RunConfirm runs a minimal full-screen program asking a single yes/no question. Returns true when the user selects Yes, false for No, Esc, or Ctrl+C. Intended for simple interactive confirmations outside of a larger TUI wizard.
Types ¶
type ConfirmField ¶
type ConfirmField struct {
// contains filtered or unexported fields
}
ConfirmField is a yes/no two-option select bound to a *bool. ↑/← or y sets Yes; ↓/→ or n sets No.
func NewConfirmField ¶
func NewConfirmField(title, desc string, ptr *bool) *ConfirmField
NewConfirmField creates a ConfirmField bound to ptr. The initial selection reflects *ptr: true → Yes (cursor 0), false → No (cursor 1).
func (*ConfirmField) Blur ¶
func (f *ConfirmField) Blur()
func (*ConfirmField) Focus ¶
func (f *ConfirmField) Focus() tea.Cmd
func (*ConfirmField) Focusable ¶
func (f *ConfirmField) Focusable() bool
func (*ConfirmField) Validate ¶
func (f *ConfirmField) Validate() error
func (*ConfirmField) Value ¶
func (f *ConfirmField) Value() bool
Value returns the current boolean selection.
type Field ¶
type Field interface {
// Update handles keyboard / mouse input when this field is focused.
// Returns the (possibly mutated) field and any follow-up command.
Update(msg tea.Msg) (Field, tea.Cmd)
// View renders the field to a string. focused controls cursor / highlight
// visibility. width is the available horizontal space in terminal columns.
View(focused bool, width int) string
// Focus activates the field (shows cursor, starts blink animation, etc.)
// and returns any initialisation command required.
Focus() tea.Cmd
// Blur deactivates the field (hides cursor, dims colours, etc.).
Blur()
// Focusable returns false for purely decorative / read-only fields (e.g.
// NoteField) that the Screen should skip when cycling focus.
Focusable() bool
// Validate returns a non-nil error when the field's current value is
// invalid. Called by the Screen before advancing focus or submitting.
Validate() error
}
Field is the interface implemented by every interactive element in a Screen.
All concrete types (*TextField, *SelectField, etc.) use pointer receivers so they satisfy the interface while being mutated in-place inside a Screen's field slice – no extra copying overhead per frame.
type Keys ¶
type Keys struct {
Up key.Binding
Down key.Binding
Tab key.Binding
ShiftTab key.Binding
Enter key.Binding
Space key.Binding
Esc key.Binding
Quit key.Binding
}
Keys holds all key bindings used by GDG TUI screens. It implements help.KeyMap so it can be passed directly to help.Model.View().
type MultiSelectField ¶
type MultiSelectField struct {
// contains filtered or unexported fields
}
MultiSelectField renders a checklist of options.
Key bindings (writable mode):
↑ / k — move cursor up ↓ / j — move cursor down space — toggle the focused item enter — confirm selection and advance / submit the screen
In read-only mode the cursor still moves but Space is ignored. Use WithReadOnly() to create a display-only list (e.g. showing which files will be affected before the user confirms).
Selected values are synced live to *ptr (slice of option Values).
func NewMultiSelectField ¶
func NewMultiSelectField(title, desc string, opts []Option, ptr *[]string) *MultiSelectField
NewMultiSelectField creates a writable MultiSelectField bound to ptr. Options whose Value appears in *ptr are pre-checked.
func (*MultiSelectField) Blur ¶
func (f *MultiSelectField) Blur()
func (*MultiSelectField) Focus ¶
func (f *MultiSelectField) Focus() tea.Cmd
func (*MultiSelectField) Focusable ¶
func (f *MultiSelectField) Focusable() bool
func (*MultiSelectField) Validate ¶
func (f *MultiSelectField) Validate() error
func (*MultiSelectField) WithItemSelected ¶
func (f *MultiSelectField) WithItemSelected(value string, sel bool) *MultiSelectField
WithItemSelected pre-selects or deselects a single option by value.
func (*MultiSelectField) WithReadOnly ¶
func (f *MultiSelectField) WithReadOnly() *MultiSelectField
WithReadOnly returns a copy of the field configured for display only. The cursor can still move for readability, but Space does not toggle items. Focusable() still returns true so the screen cycles through it normally.
func (*MultiSelectField) WithSelected ¶
func (f *MultiSelectField) WithSelected(values []string) *MultiSelectField
WithSelected pre-selects the options whose values are in the provided slice, replacing any prior selection. Useful for setting defaults after construction.
func (*MultiSelectField) WithValidate ¶
func (f *MultiSelectField) WithValidate(fn func([]string) error) *MultiSelectField
WithValidate attaches a validation function (e.g. "at least one required"). Validation is skipped in read-only mode.
type NoteField ¶
type NoteField struct {
// contains filtered or unexported fields
}
NoteField is a read-only informational panel. It is not focusable; the Screen skips it when cycling focus. Pressing Enter on a screen whose only fields are NoteFields submits the screen immediately (the user just needs to acknowledge the information and move on).
func NewNoteField ¶
NewNoteField creates an informational display field.
type Screen ¶
type Screen struct {
Submitted bool
Cancelled bool
ErrMsg string // screen-level error (e.g. from multi-field validation)
// contains filtered or unexported fields
}
Screen manages a list of Fields for one wizard step.
Responsibilities:
- Tab / Shift-Tab cycle focus through focusable fields (wrapping).
- Enter validates the current field and advances focus, or submits the screen when the last focusable field is confirmed.
- Esc sets Cancelled = true (the parent model decides what "back" means).
- Ctrl+C is intentionally NOT handled here; the parent model intercepts it.
After Update returns, callers check:
screen.Submitted — all fields valid, phase may advance screen.Cancelled — user pressed Esc, phase should go back
Field values are bound to external pointers at construction time, so the parent can read results directly from its state struct without extracting them from the Screen.
func NewScreen ¶
NewScreen creates a Screen with the given width and fields.
The first focusable field is identified immediately so that key events are routed correctly even before Init() is called. This matters because bubbletea v2's Init() returns only a tea.Cmd — model mutations inside Init() are discarded — so we cannot rely on Init() to set the focus index.
func (Screen) Init ¶
Init fires the Focus() command on the already-focused field so that textinput components start with their cursor blinking immediately. The focus *index* is set in NewScreen rather than here because bubbletea v2 discards model-level mutations made inside Init().
type SelectField ¶
type SelectField struct {
// contains filtered or unexported fields
}
SelectField renders a single-choice list. ↑/↓ (or k/j) move the cursor; the selected value is synced live to *ptr.
func NewSelectField ¶
func NewSelectField(title, desc string, opts []Option, ptr *string) *SelectField
NewSelectField creates a SelectField bound to ptr. The option whose Value matches *ptr is pre-selected; if *ptr is empty the first option is selected and *ptr is updated accordingly.
func (*SelectField) Blur ¶
func (f *SelectField) Blur()
func (*SelectField) Focus ¶
func (f *SelectField) Focus() tea.Cmd
func (*SelectField) Focusable ¶
func (f *SelectField) Focusable() bool
func (*SelectField) Validate ¶
func (f *SelectField) Validate() error
func (*SelectField) Value ¶
func (f *SelectField) Value() string
Value returns the currently highlighted option's value.
type TextField ¶
type TextField struct {
// contains filtered or unexported fields
}
TextField wraps a bubbles textinput.Model, binding its live value to an external *string pointer so callers can read the result without an extra step after the screen is submitted.
func NewTextField ¶
NewTextField creates a TextField with title, description, and a bound pointer. If ptr already holds a non-empty string the input is pre-filled.
func (*TextField) SetError ¶
SetError displays an inline error message (used by Screen on validation failure).
func (*TextField) WithPlaceholder ¶
WithPlaceholder sets greyed-out placeholder text shown when the field is empty.