bubbletea Documentation

A powerful little TUI framework 🏗

RAW Doc

Technical Documentation: charmbracelet/bubbletea

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

Bubble Tea

text
[](https://github.com/charmbracelet/bubbletea/releases)
[](https://pkg.go.dev/charm.land/bubbletea/v2?tab=doc)
[](https://github.com/charmbracelet/bubbletea/actions)

The fun, functional and stateful way to build terminal apps. A Go framework
based on The Elm Architecture. Bubble Tea is well-suited for simple and
complex terminal applications, either inline, full-window, or a mix of both.

Bubble Tea is in use in production and includes a number of features and
performance optimizations we’ve added along the way. Among those is
a high-performance cell-based renderer, built-in color downsampling,
declarative views, high-fidelity keyboard and mouse handling, native clipboard
support, and more.

To get started, see the tutorial below, the examples, the
docs, and some common resources.

[!TIP]

Upgrading from v1? Check out the upgrade guide, or
point your LLM at it and let it go to town.

By the way

Be sure to check out Bubbles, a library of common UI components for Bubble Tea.

text
[](https://github.com/charmbracelet/bubbles)  
[](https://github.com/charmbracelet/bubbles)

Tutorial

Bubble Tea is based on the functional design paradigms of The Elm
Architecture
, which happens to work nicely with Go. It's a delightful way
to build applications.

This tutorial assumes you have a working knowledge of Go.

By the way, the non-annotated source code for this program is available
on GitHub.

Enough! Let's get to it.

For this tutorial, we're making a shopping list.

To start we'll define our package and import some libraries. Our only external
import will be the Bubble Tea library, which we'll call tea for short.

go
package main

// These imports will be used later in the tutorial. If you save the file
// now, Go might complain they are unused, but that's fine.
// You may also need to run `go mod tidy` to download bubbletea and its
// dependencies.
import (
    "fmt"
    "os"

    tea "charm.land/bubbletea/v2"
)

Bubble Tea programs are comprised of a model that describes the application
state and three simple methods on that model:

  • Init, a function that returns an initial command for the application to run.
  • Update, a function that handles incoming events and updates the model accordingly.
  • View, a function that renders the UI based on the data in the model.

The Model

So let's start by defining our model which will store our application's state.
It can be any type, but a struct usually makes the most sense.

go
type model struct {
    choices  []string           // items on the to-do list
    cursor   int                // which to-do list item our cursor is pointing at
    selected map[int]struct{}   // which to-do items are selected
}

Initialization

Next, we’ll define our application’s initial state. Init can return a Cmd
that could perform some initial I/O. For now, we don’t need to do any I/O, so
for the command, we’ll just return nil, which translates to “no command.”

go
func initialModel() model {
	return model{
		// Our to-do list is a grocery list
		choices:  []string{"Buy carrots", "Buy celery", "Buy kohlrabi"},

		// A map which indicates which choices are selected. We're using
		// the  map like a mathematical set. The keys refer to the indexes
		// of the `choices` slice, above.
		selected: make(map[int]struct{}),
	}
}

After that, we’ll define our application’s initial state in the Init method. Init
can return a Cmd that could perform some initial I/O. For now, we don't need
to do any I/O, so for the command, we'll just return nil, which translates to
"no command."

go
func (m model) Init() tea.Cmd {
    // Just return `nil`, which means "no I/O right now, please."
    return nil
}

The Update Method

Next up is the update method. The update function is called when “things
happen.” Its job is to look at what has happened and return an updated model in
response. It can also return a Cmd to make more things happen, but for now
don't worry about that part.

In our case, when a user presses the down arrow, Update’s job is to notice
that the down arrow was pressed and move the cursor accordingly (or not).

The “something happened” comes in the form of a Msg, which can be any type.
Messages are the result of some I/O that took place, such as a keypress, timer
tick, or a response from a server.

We usually figure out which type of Msg we received with a type switch, but
you could also use a type assertion.

For now, we'll just deal with tea.KeyPressMsg messages, which are
automatically sent to the update function when keys are pressed.

go
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {

    // Is it a key press?
    case tea.KeyPressMsg:

        // Cool, what was the actual key pressed?
        switch msg.String() {

        // These keys should exit the program.
        case "ctrl+c", "q":
            return m, tea.Quit

        // The "up" and "k" keys move the cursor up
        case "up", "k":
            if m.cursor > 0 {
                m.cursor--
            }

        // The "down" and "j" keys move the cursor down
        case "down", "j":
            if m.cursor < len(m.choices)-1 {
                m.cursor++
            }

        // The "enter" key and the space bar toggle the selected state
        // for the item that the cursor is pointing at.
        case "enter", "space":
            _, ok := m.selected[m.cursor]
            if ok {
                delete(m.selected, m.cursor)
            } else {
                m.selected[m.cursor] = struct{}{}
            }
        }
    }

    // Return the updated model to the Bubble Tea runtime for processing.
    // Note that we're not returning a command.
    return m, nil
}

You may have noticed that ctrl+c and q above return
a tea.Quit command with the model. That’s a special command which instructs
the Bubble Tea runtime to quit, exiting the program.

The View Method

At last, it’s time to render our UI. Of all the methods, the view is the
simplest. We look at the model in its current state and use it to build a
tea.View. The view declares our UI content and, optionally, terminal features
like alt screen mode, mouse tracking, cursor position, and more.

Because the view describes the entire UI of your application, you don’t have to
worry about redrawing logic and stuff like that. Bubble Tea takes care of it
for you.

go
func (m model) View() tea.View {
    // The header
    s := "What should we buy at the market?\n\n"

    // Iterate over our choices
    for i, choice := range m.choices {

        // Is the cursor pointing at this choice?
        cursor := " " // no cursor
        if m.cursor == i {
            cursor = ">" // cursor!
        }

        // Is this choice selected?
        checked := " " // not selected
        if _, ok := m.selected[i]; ok {
            checked = "x" // selected!
        }

        // Render the row
        s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice)
    }

    // The footer
    s += "\nPress q to quit.\n"

    // Send the UI for rendering
    return tea.NewView(s)
}

All Together Now

The last step is to simply run our program. We pass our initial model to
tea.NewProgram and let it rip:

go
func main() {
    p := tea.NewProgram(initialModel())
    if _, err := p.Run(); err != nil {
        fmt.Printf("Alas, there's been an error: %v", err)
        os.Exit(1)
    }
}

What’s Next?

This tutorial covers the basics of building an interactive terminal UI, but
in the real world you'll also need to perform I/O. To learn about that have a
look at the Command Tutorial. It's pretty simple.

There are also several Bubble Tea examples available and, of course,
there are Go Docs.

Debugging

Debugging with Delve

Since Bubble Tea apps assume control of stdin and stdout, you’ll need to run
delve in headless mode and then connect to it:

bash
# Start the debugger
$ dlv debug --headless --api-version=2 --listen=127.0.0.1:43000 .
API server listening at: 127.0.0.1:43000

# Connect to it from another terminal
$ dlv connect 127.0.0.1:43000

If you do not explicitly supply the --listen flag, the port used will vary
per run, so passing this in makes the debugger easier to use from a script
or your IDE of choice.

Additionally, we pass in --api-version=2 because delve defaults to version 1
for backwards compatibility reasons. However, delve recommends using version 2
for all new development and some clients may no longer work with version 1.
For more information, see the Delve documentation.

Logging Stuff

You can’t really log to stdout with Bubble Tea because your TUI is busy
occupying that! You can, however, log to a file by including something like
the following prior to starting your Bubble Tea program:

go
if len(os.Getenv("DEBUG")) > 0 {
	f, err := tea.LogToFile("debug.log", "debug")
	if err != nil {
		fmt.Println("fatal:", err)
		os.Exit(1)
	}
	defer f.Close()
}

To see what’s being logged in real time, run tail -f debug.log while you run
your program in another window.

Libraries we use with Bubble Tea

  • Bubbles: Common Bubble Tea components such as text inputs, viewports, spinners and so on
  • Lip Gloss: Style, format and layout tools for terminal applications
  • Harmonica: A spring animation library for smooth, natural motion
  • BubbleZone: Easy mouse event tracking for Bubble Tea components
  • ntcharts: A terminal charting library built for Bubble Tea and Lip Gloss

Bubble Tea in the Wild

There are over 18,000 applications built with Bubble Tea! Here are a handful of ’em.

Staff favourites

  • chezmoi: securely manage your dotfiles across multiple machines
  • circumflex: read Hacker News in the terminal
  • gh-dash: a GitHub CLI extension for PRs and issues
  • Tetrigo: Tetris in the terminal
  • Signls: a generative midi sequencer designed for composition and live performance
  • Superfile: a super file manager

In Industry

  • Microsoft Azure – Aztify: bring Microsoft Azure resources under Terraform
  • Daytona – Daytona: an AI infrastructure platform
  • Cockroach Labs – CockroachDB: a cloud-native, high-availability distributed SQL database
  • Truffle Security Co. – Trufflehog: find leaked credentials
  • NVIDIA – container-canary: a container validator
  • AWS – eks-node-viewer: a tool for visualizing dynamic node usage within an EKS cluster
  • MinIO – mc: the official MinIO client
  • Ubuntu – Authd: an authentication daemon for cloud-based identity providers

Charm stuff

  • Glow: a markdown reader, browser, and online markdown stash
  • Huh?: an interactive prompt and form toolkit
  • Mods: AI on the CLI, built for pipelines
  • Wishlist: an SSH directory (and bastion!)

There’s so much more where that came from

For more applications built with Bubble Tea see Charm & Friends.
Is there something cool you made with Bubble Tea you want to share? PRs are
welcome!

Contributing

See contributing.

Feedback

We’d love to hear your thoughts on this project. Feel free to drop us a note!

Acknowledgments

Bubble Tea is based on the paradigms of The Elm Architecture by Evan
Czaplicki et alia and the excellent go-tea by TJ Holowaychuk. It’s
inspired by the many great Zeichenorientierte Benutzerschnittstellen
of days past.

License

MIT


Part of Charm.

Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة


Overview (`examples/README.md`)

Examples

Alt Screen Toggle

The altscreen-toggle example shows how to transition between the alternative
screen buffer and the normal screen buffer using Bubble Tea.

Chat

The chat examples shows a basic chat application with a multi-line textarea
input.

Composable Views

The composable-views example shows how to compose two bubble models (spinner
and timer) together in a single application and switch between them.

ISBN Book Form

The isbn-form example demonstrates how to build a multi-step form with
textinput bubbles and validation on the inputs.

Debounce

The debounce example shows how to throttle key presses to avoid overloading
your Bubble Tea application.

Exec

The exec example shows how to execute a running command during the execution
of a Bubble Tea application such as launching an EDITOR.

Full Screen

The fullscreen example shows how to make a Bubble Tea application fullscreen.

Glamour

The glamour example shows how to use Glamour inside a viewport bubble.

Help

The help example shows how to use the help bubble to display help to the
user of your application.

Http

The http example shows how to make an http call within your Bubble Tea
application.

Default List

The list-default example shows how to use the list bubble.

Fancy List

The list-fancy example shows how to use the list bubble with extra customizations.

Simple List

The list-simple example shows how to use the list and customize it to have a simpler, more compact, appearance.

Mouse

The mouse example shows how to receive mouse events in a Bubble Tea
application.

Code

Package Manager

The package-manager example shows how to build an interface for a package
manager using the tea.Println feature.

Pager

The pager example shows how to build a simple pager application similar to
less.

Paginator

The paginator example shows how to build a simple paginated list.

Pipe

The pipe example demonstrates using shell pipes to communicate with Bubble
Tea applications.

Animated Progress

The progress-animated example shows how to build a progress bar with an
animated progression.

Download Progress

The progress-download example demonstrates how to download a file while
indicating download progress through Bubble Tea.

Code

Static Progress

The progress-static example shows a progress bar with static incrementation
of progress.

Real Time

The realtime example demonstrates the use of go channels to perform realtime
communication with a Bubble Tea application.

Result

The result example shows a choice menu with the ability to select an option.

Send Msg

The send-msg example demonstrates the usage of custom tea.Msgs.

Sequence

The sequence example demonstrates the tea.Sequence command.

Simple

The simple example shows a very simple Bubble Tea application.

Spinner

The spinner example demonstrates a spinner bubble being used to indicate loading.

Spinners

The spinner example shows various spinner types that are available.

Split Editors

The split-editors example shows multiple textareas being used in a single
application and being able to switch focus between them.

Stop Watch

The stopwatch example shows a sample stop watch built with Bubble Tea.

Table

The table example demonstrates the table bubble being used to display tabular
data.

Tabs

The tabs example demonstrates tabbed navigation styled with Lip Gloss.

Text Area

The textarea example demonstrates a simple Bubble Tea application using a
textarea bubble.

Text Input

The textinput example demonstrates a simple Bubble Tea application using a textinput bubble.

Multiple Text Inputs

The textinputs example shows multiple textinputs and being able to switch
focus between them as well as changing the cursor mode.

Timer

The timer example shows a simple timer built with Bubble Tea.

TUI Daemon

The tui-daemon-combo demonstrates building a text-user interface along with a
daemon mode using Bubble Tea.

Views

The views example demonstrates how to build a Bubble Tea application with
multiple views and switch between them.


Overview (`examples/altscreen-toggle/README.md`)

Alt Screen Toggle


Overview (`examples/composable-views/README.md`)

Composable Views


Overview (`examples/debounce/README.md`)

Debounce


Overview (`examples/fullscreen/README.md`)

Full Screen


Overview (`examples/glamour/README.md`)

Glamour


Overview (`examples/list-default/README.md`)

Default List


Overview (`examples/list-fancy/README.md`)

Fancy List


Overview (`examples/list-simple/README.md`)

Simple List


Overview (`examples/package-manager/README.md`)

Package Manager


Overview (`examples/paginator/README.md`)

Paginator


Overview (`examples/progress-animated/README.md`)

Animated Progress


Overview (`examples/progress-download/README.md`)

Download Progress

This example demonstrates how to download a file from a URL and show its
progress with a Progress Bubble.

In this case we're getting download progress with an io.TeeReader and
sending progress Msgs to the Program with Program.Send().

How to Run

Build the application with go build ., then run with a --url argument
specifying the URL of the file to download. For example:

text
./progress-download --url="https://download.blender.org/demo/color_vortex.blend"

Note that in this example a TUI will not be shown for URLs that do not respond
with a ContentLength header.


This example originally came from this discussion.


Charm热爱开源 • Charm loves open source


Overview (`examples/progress-static/README.md`)

Static Progress


Overview (`examples/realtime/README.md`)

Real Time


Overview (`examples/send-msg/README.md`)

Send Msg


Overview (`examples/sequence/README.md`)

Sequence


Overview (`examples/spinner/README.md`)

Spinner


Overview (`examples/spinners/README.md`)

Spinners


Overview (`examples/split-editors/README.md`)

Split Editors


Overview (`examples/stopwatch/README.md`)

Stopwatch


Overview (`examples/textarea/README.md`)

Text Area


Overview (`examples/textinput/README.md`)

Text Input


Overview (`examples/textinputs/README.md`)

Text Inputs


Overview (`examples/tui-daemon-combo/README.md`)

TUI Daemon


Overview (`tutorials/basics/README.md`)

Bubble Tea Basics

Bubble Tea is based on the functional design paradigms of The Elm
Architecture
, which happens to work nicely with Go. It’s a delightful way
to build applications.

This tutorial assumes you have a working knowledge of Go.

By the way, the non-annotated source code for this program is available
on GitHub.

Enough! Let’s get to it.

For this tutorial, we’re making a shopping list.

To start we’ll define our package and import some libraries. Our only external
import will be the Bubble Tea library, which we’ll call tea for short.

go
package main

import (
    "fmt"
    "os"

    tea "charm.land/bubbletea/v2"
)

Bubble Tea programs are comprised of a model that describes the application
state and three simple methods on that model:

  • Init, a function that returns an initial command for the application to run.
  • Update, a function that handles incoming events and updates the model accordingly.
  • View, a function that renders the UI based on the data in the model.

The Model

So let’s start by defining our model which will store our application’s state.
It can be any type, but a struct usually makes the most sense.

go
type model struct {
    choices  []string           // items on the to-do list
    cursor   int                // which to-do list item our cursor is pointing at
    selected map[int]struct{}   // which to-do items are selected
}

Initialization

Next, we’ll define our application’s initial state. In this case, we’re defining
a function to return our initial model, however, we could just as easily define
the initial model as a variable elsewhere, too.

go
func initialModel() model {
	return model{
		// Our to-do list is a grocery list
		choices:  []string{"Buy carrots", "Buy celery", "Buy kohlrabi"},

		// A map which indicates which choices are selected. We're using
		// the map like a mathematical set. The keys refer to the indexes
		// of the `choices` slice, above.
		selected: make(map[int]struct{}),
	}
}

After that, we’ll define the Init method. Init can return a Cmd that
could perform some initial I/O. For now, we don’t need to do any I/O, so for
the command, we’ll just return nil, which translates to "no command."

go
func (m model) Init() tea.Cmd {
    return nil
}

The Update Method

Next up is the update method. The update function is called when “things
happen.” Its job is to look at what has happened and return an updated model in
response. It can also return a Cmd to make more things happen, but for now
don’t worry about that part.

In our case, when a user presses the down arrow, Update’s job is to notice
that the down arrow was pressed and move the cursor accordingly (or not).

The “something happened” comes in the form of a Msg, which can be any type.
Messages are the result of some I/O that took place, such as a keypress, timer
tick, or a response from a server.

We usually figure out which type of Msg we received with a type switch, but
you could also use a type assertion.

For now, we’ll just deal with tea.KeyPressMsg messages, which are
automatically sent to the update function when keys are pressed.

go
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {

    // Is it a key press?
    case tea.KeyPressMsg:

        // Cool, what was the actual key pressed?
        switch msg.String() {

        // These keys should exit the program.
        case "ctrl+c", "q":
            return m, tea.Quit

        // The "up" and "k" keys move the cursor up
        case "up", "k":
            if m.cursor > 0 {
                m.cursor--
            }

        // The "down" and "j" keys move the cursor down
        case "down", "j":
            if m.cursor < len(m.choices)-1 {
                m.cursor++
            }

        // The enter key and the space bar toggle the selected state for the
        // item that the cursor is pointing at.
        case "enter", "space":
            _, ok := m.selected[m.cursor]
            if ok {
                delete(m.selected, m.cursor)
            } else {
                m.selected[m.cursor] = struct{}{}
            }
        }
    }

    // Return the updated model to the Bubble Tea runtime for processing.
    // Note that we're not returning a command.
    return m, nil
}

You may have noticed that ctrl+c and q above return
a tea.Quit command with the model. That’s a special command which instructs
the Bubble Tea runtime to quit, exiting the program.

The View Method

At last, it’s time to render our UI. Of all the methods, the view is the
simplest. We look at the model in its current state and use it to return
a tea.View. The view declares our UI content and, optionally, terminal
features like full-window mode (aka, altscreen mode), mouse tracking, cursor
position, and more.

Because the view describes the entire UI of your application, you don’t have to
worry about redrawing logic and stuff like that. Bubble Tea takes care of it
for you.

go
func (m model) View() tea.View {
    // The header
    s := "What should we buy at the market?\n\n"

    // Iterate over our choices
    for i, choice := range m.choices {

        // Is the cursor pointing at this choice?
        cursor := " " // no cursor
        if m.cursor == i {
            cursor = ">" // cursor!
        }

        // Is this choice selected?
        checked := " " // not selected
        if _, ok := m.selected[i]; ok {
            checked = "x" // selected!
        }

        // Render the row
        s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice)
    }

    // The footer
    s += "\nPress q to quit.\n"

    // Send the UI for rendering
    return tea.NewView(s)
}

All Together Now

The last step is to simply run our program. We pass our initial model to
tea.NewProgram and let it rip:

go
func main() {
    p := tea.NewProgram(initialModel())
    if _, err := p.Run(); err != nil {
        fmt.Printf("Alas, there's been an error: %v", err)
        os.Exit(1)
    }
}

What’s Next?

This tutorial covers the basics of building an interactive terminal UI, but
in the real world you’ll also need to perform I/O. To learn about that have a
look at the Command Tutorial. It’s pretty simple.

There are also several Bubble Tea examples available and, of course,
there are Go Docs.

Additional Resources

Feedback

We’d love to hear your thoughts on this tutorial. Feel free to drop us a note!


Part of Charm.

Charm热爱开源 • Charm loves open source


Overview (`tutorials/commands/README.md`)

Commands in Bubble Tea

This is the second tutorial for Bubble Tea covering commands, which deal with
I/O. The tutorial assumes you have a working knowledge of Go and a decent
understanding of the first tutorial.

You can find the non-annotated version of this program on GitHub.

Let’s Go!

For this tutorial we’re building a very simple program that makes an HTTP
request to a server and reports the status code of the response.

We’ll import a few necessary packages and put the URL we’re going to check in
a const.

go
package main

import (
    "fmt"
    "net/http"
    "os"
    "time"

    tea "charm.land/bubbletea/v2"
)

const url = "https://charm.sh/"

The Model

Next we’ll define our model. The only things we need to store are the status
code of the HTTP response and a possible error.

go
type model struct {
    status int
    err    error
}

Commands and Messages

Cmds are functions that perform some I/O and then return a Msg. Checking the
time, ticking a timer, reading from the disk, and network stuff are all I/O and
should be run through commands. That might sound harsh, but it will keep your
Bubble Tea program straightforward and simple.

Anyway, let’s write a Cmd that makes a request to a server and returns the
result as a Msg.

go
func checkServer() tea.Msg {

    // Create an HTTP client and make a GET request.
    c := &http.Client{Timeout: 10 * time.Second}
    res, err := c.Get(url)

    if err != nil {
        // There was an error making our request. Wrap the error we received
        // in a message and return it.
        return errMsg{err}
    }
    // We received a response from the server. Return the HTTP status code
    // as a message.
    return statusMsg(res.StatusCode)
}

type statusMsg int

type errMsg struct{ err error }

// For messages that contain errors it's often handy to also implement the
// error interface on the message.
func (e errMsg) Error() string { return e.err.Error() }

And notice that we’ve defined two new Msg types. They can be any type, even
an empty struct. We’ll come back to them later in our update function.
First, let’s write our initialization function.

The Initialization Method

The initialization method is very simple: we return the Cmd we made earlier.
Note that we don’t call the function; the Bubble Tea runtime will do that when
the time is right.

go
func (m model) Init() tea.Cmd {
    return checkServer
}

The Update Method

Internally, Cmds run asynchronously in a goroutine. The Msg they return is
collected and sent to our update function for handling. Remember those message
types we made earlier when we were making the checkServer command? We handle
them here. This makes dealing with many asynchronous operations very easy.

go
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {

    case statusMsg:
        // The server returned a status message. Save it to our model. Also
        // tell the Bubble Tea runtime we want to exit because we have nothing
        // else to do. We'll still be able to render a final view with our
        // status message.
        m.status = int(msg)
        return m, tea.Quit

    case errMsg:
        // There was an error. Note it in the model. And tell the runtime
        // we're done and want to quit.
        m.err = msg
        return m, tea.Quit

    case tea.KeyPressMsg:
        // Ctrl+c exits. Even with short running programs it's good to have
        // a quit key, just in case your logic is off. Users will be very
        // annoyed if they can't exit.
		if msg.Mod == tea.ModCtrl && msg.Code == 'c' {
			return m, tea.Quit
		}
    }

    // If we happen to get any other messages, don't do anything.
    return m, nil
}

The View Function

Our view is very straightforward. We look at the current model and build a
tea.View accordingly:

go
func (m model) View() tea.View {
    // If there's an error, print it out and don't do anything else.
    if m.err != nil {
        return tea.NewView(fmt.Sprintf("\nWe had some trouble: %v\n\n", m.err))
    }

    // Tell the user we're doing something.
    s := fmt.Sprintf("Checking %s ... ", url)

    // When the server responds with a status, add it to the current line.
    if m.status > 0 {
        s += fmt.Sprintf("%d %s!", m.status, http.StatusText(m.status))
    }

    // Send off whatever we came up with above for rendering.
    return tea.NewView("\n" + s + "\n\n")
}

Run the program

The only thing left to do is run the program, so let’s do that! Our initial
model doesn’t need any data at all in this case, we just initialize it with
a model struct with default values.

go
func main() {
    if _, err := tea.NewProgram(model{}).Run(); err != nil {
        fmt.Printf("Uh oh, there was an error: %v\n", err)
        os.Exit(1)
    }
}

And that’s that. There’s one more thing that is helpful to know about
Cmds, though.

One More Thing About Commands

Cmds are defined in Bubble Tea as type Cmd func() Msg. So they’re just
functions that don’t take any arguments and return a Msg, which can be
any type. If you need to pass arguments to a command, you just make a function
that returns a command. For example:

go
func cmdWithArg(id int) tea.Cmd {
    return func() tea.Msg {
        return someMsg{id: id}
    }
}

A more real-world example looks like:

go
func checkSomeUrl(url string) tea.Cmd {
    return func() tea.Msg {
        c := &http.Client{Timeout: 10 * time.Second}
        res, err := c.Get(url)
        if err != nil {
            return errMsg{err}
        }
        return statusMsg(res.StatusCode)
    }
}

Anyway, just make sure you do as much stuff as you can in the innermost
function, because that’s the one that runs asynchronously.

Now What?

After doing this tutorial and the previous one you should be ready to
build a Bubble Tea program of your own. We also recommend that you look at the
Bubble Tea example programs as well as Bubbles,
a component library for Bubble Tea.

And, of course, check out the Go Docs.

Additional Resources

Feedback

We’d love to hear your thoughts on this tutorial. Feel free to drop us a note!


Part of Charm.

Charm热爱开源 • Charm loves open source


--- METRICS ---