Focus Management
Relevant source files
The following files were used as context for generating this wiki page:
Focus Management in the Wizard Tutorial project refers to the mechanism by which the application controls which input component is active and receiving user keyboard events at any given time. In a terminal-based wizard, focus must be programmatically shifted between different questions and their associated input fields (short text or long text) as the user progresses through the sequence.
The system relies on the Bubble Tea framework's Elm-like architecture, where the state of focus is managed through commands (tea.Cmd) and messages (tea.Msg). Each input component implements a unified interface to ensure that the main application logic can toggle focus and cursor blinking consistently across different input types.
Sources: main.go:41-65, input.go:9-18, README.md:1-12
The Input Interface
Central to focus management is the Input interface. This interface abstracts the underlying Bubble components (such as textinput and textarea) so the main model can manage focus without knowing the specific implementation details of the field.
type Input interface {
Blink() tea.Msg
Blur() tea.Msg
Focus() tea.Cmd
SetValue(string)
Value() string
Update(tea.Msg) (Input, tea.Cmd)
View() string
}
Sources: input.go:9-18
Focus-Related Methods
The interface defines three critical methods for focus control:
- Focus(): Returns a
tea.Cmdthat initiates the focus state for the component, enabling keyboard input capture. - Blur(): Returns a
tea.Msgthat signals the component to relinquish focus. - Blink(): Returns a
tea.Msgused to handle cursor blinking animations, which are only active when a component is focused.
Sources: input.go:11-13, input.go:57-59, input.go:65-67
Architecture and Data Flow
The focus state is managed by the Main struct, which tracks the current index of the active question. When the index changes, the application must ensure the previous input is blurred and the new input is focused.
Component Hierarchy
The following class diagram illustrates the relationship between the Main controller and the focusable input components.
The Main model contains a slice of Question objects, each holding an implementation of the Input interface.
Sources: main.go:23-30, main.go:32-36, input.go:9-18
Focus Transition Logic
When a user presses the "enter" key, the Update loop handles the transition of focus from the current input to the next one in the sequence.
| Event | Action | Focus Change |
|---|---|---|
Init | Start application | Blinks the first input in questions[0]. |
enter Key | Move to next question | Calls input.Blur on the current field and increments the index. |
Next() | Update internal index | Loops back to 0 or advances to the next question object. |
Sources: main.go:67-93, main.go:121-127
Focus Flow Sequence
The sequence below demonstrates how focus is handled during a transition between questions.
The transition is triggered by the "enter" key, resulting in the current input's value being saved and the model advancing to the next index.
Sources: main.go:82-90, main.go:121-127
Implementation Details
Short vs. Long Answer Fields
Both shortAnswerField (wrapping textinput) and longAnswerField (wrapping textarea) set focus immediately upon instantiation using the internal component's .Focus() method.
func NewShortAnswerField() *shortAnswerField {
a := shortAnswerField{}
model := textinput.New()
model.Focus() // Set initial focus
a.textinput = model
return &a
}
Sources: input.go:27-32, input.go:76-81
View Rendering and Focus Styles
The focused input is rendered within a styled border defined in the Styles struct. The application uses lipgloss to join the question text and the active (focused) input field vertically.
| Component | Style/Method | Description |
|---|---|---|
InputField | lipgloss.Style | Defines the border color ("36") and padding for the focused area. |
View() | current.input.View() | Renders the visual representation of the input, including the cursor. |
Sources: main.go:13-21, main.go:108-118
Summary
Focus management in this project is achieved through a structured interface that wraps Charm Cloud's UI components. By abstracting focus, blur, and blink operations, the Main model can fluidly navigate a series of questions, ensuring that only one input field is interactive at a time while maintaining a consistent user experience.