Sequence
What This Example Shows
This example demonstrates how to use tea.Sequence to execute commands in a strict order, ensuring each completes before the next starts. It combines tea.Sequence with tea.Batch for concurrent sub-tasks within the sequence.
The key here is tea.Sequence, which runs commands sequentially, waiting for each message to be processed before proceeding—ideal for ordered operations like initialization or animations.
Understanding Sequential Commands in Bubble Tea
tea.Sequence runs a series of commands one after another, only starting the next after the previous command's message has been handled in Update. This contrasts with tea.Batch, which starts all commands concurrently without order guarantees.
This is useful for scenarios requiring step-by-step execution, preventing overlap in tasks like printing messages or performing setup.
This approach is perfect for creating predictable flows in your app, such as phased loading or sequenced outputs, while still allowing concurrency where needed via nested batches.
Here's what happens:
- The sequence starts with a batch printing "A", "B", "C" concurrently
- After the batch completes, it prints "Z"
- Finally, it quits the program
How It Works
Set Up the Sequence
In Init, return a sequence of commands:
return tea.Sequence(
tea.Batch(
tea.Println("A"),
tea.Println("B"),
tea.Println("C"),
),
tea.Println("Z"),
tea.Quit,
)Batch runs concurrently; sequence ensures order.
Handle Key Presses
In Update, quit on any key for manual exit:
switch msg.(type) {
case tea.KeyMsg:
return m, tea.Quit
}Though the sequence handles auto-quit.
Minimal Rendering
View returns empty as output is via Println:
func (m model) View() string {
return ""
}All display is command-driven.
Sequence relies on messages being processed; complex commands might need careful handling to avoid unexpected delays.
Code Breakdown
Empty model as state isn't needed:
type model struct{}Simple struct for minimal app.
Initialize and run:
func main() {
if _, err := tea.NewProgram(model{}).Run(); err != nil {
fmt.Println("Uh oh:", err)
os.Exit(1)
}
}
func (m model) Init() tea.Cmd {
// Sequence here
}Run handles execution.
Core init logic:
func (m model) Init() tea.Cmd {
return tea.Sequence(
tea.Batch(
tea.Println("A"),
tea.Println("B"),
tea.Println("C"),
),
tea.Println("Z"),
tea.Quit,
)
}Ordered execution with concurrent sub-group.
Minimal update:
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.(type) {
case tea.KeyMsg:
return m, tea.Quit
}
return m, nil
}Only for manual quit.
The View
No persistent UI; returns empty string:
func (m model) View() string {
return ""
}Output comes from tea.Println commands.
Final Code
package main
import (
"fmt"
"os"
tea "github.com/charmbracelet/bubbletea"
)
type model struct{}
func (m model) Init() tea.Cmd {
return tea.Sequence(
tea.Batch(
tea.Println("A"),
tea.Println("B"),
tea.Println("C"),
),
tea.Println("Z"),
tea.Quit,
)
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.(type) {
case tea.KeyMsg:
return m, tea.Quit
}
return m, nil
}
func (m model) View() string {
return ""
}
func main() {
if _, err := tea.NewProgram(model{}).Run(); err != nil {
fmt.Println("Uh oh:", err)
os.Exit(1)
}
}How is this guide?