charmbracelet/bubbletea
Mouse
Active contributors: aymanbagabas, meowgorithm
Purpose
Bubble Tea programs can opt into mouse input by setting View.MouseMode. The runtime handles enabling SGR and X10 mouse modes, parsing mouse events, and delivering them as typed messages.
Enabling mouse mode
mouse.go defines three modes (defined as MouseMode in tea.go):
| Mode | Effect |
|---|---|
MouseModeNone |
Mouse disabled (default). |
MouseModeCellMotion |
Click, release, wheel, and drag (motion while a button is pressed). |
MouseModeAllMotion |
All of the above plus motion when no button is pressed. |
func (m model) View() tea.View {
v := tea.NewView("Hello")
v.MouseMode = tea.MouseModeCellMotion
return v
}The renderer issues CSI ? 1000 h (button events) plus CSI ? 1006 h (SGR extended coordinates) for cell motion, or CSI ? 1003 h (any event) plus SGR for all motion.
Message types
The MouseMsg interface (mouse.go) covers four typed sub-messages. All embed a common Mouse struct (X, Y, Button, Mod).
| Message | When it fires |
|---|---|
MouseClickMsg |
Button press. |
MouseReleaseMsg |
Button release. |
MouseWheelMsg |
Scroll wheel up/down/left/right. |
MouseMotionMsg |
Pointer movement (only delivered when mouse mode is enabled, and respects CellMotion vs AllMotion). |
case tea.MouseClickMsg:
if msg.Button == tea.MouseLeft {
m.handleClick(msg.X, msg.Y)
}
case tea.MouseWheelMsg:
if msg.Button == tea.MouseWheelDown {
m.scroll(+1)
}To handle every mouse event uniformly, switch on the interface:
case tea.MouseMsg:
e := msg.Mouse()
fmt.Println(e.X, e.Y, e.Button, e.Mod)Button constants
MouseNone, MouseLeft, MouseMiddle, MouseRight,
MouseWheelUp, MouseWheelDown, MouseWheelLeft, MouseWheelRight,
MouseBackward, MouseForward, MouseButton10, MouseButton11These are aliases re-exported from uv (mouse.go).
View-level mouse handlers
View.OnMouse is an optional func(MouseMsg) Cmd that runs before the model sees a mouse message. It is called by cursedRenderer.onMouse, which is invoked from Program.eventLoop for MouseClick, MouseRelease, MouseWheel, and MouseMotion. Use it to scope mouse handling to a hit-tested area of the rendered content:
content := "Hello, World!"
v := tea.NewView(content)
v.OnMouse = func(msg tea.MouseMsg) tea.Cmd {
m := msg.Mouse()
start := strings.Index(content, "World!")
end := start + len("World!")
if m.Y == 0 && m.X >= start && m.X < end {
return func() tea.Msg { return MyHotspotMsg{} }
}
return nil
}v1 → v2 changes
The v1 MouseMsg was a struct with Action and Button fields. In v2 the message is an interface and the action is encoded by the type:
| v1 | v2 |
|---|---|
tea.WithMouseCellMotion() |
view.MouseMode = tea.MouseModeCellMotion |
tea.MouseMsg{Action: MouseActionPress} |
tea.MouseClickMsg |
tea.MouseButtonLeft |
tea.MouseLeft |
tea.MouseEvent |
tea.Mouse |
See UPGRADE_GUIDE_V2.md for the full table.
Examples
examples/mouse/main.go demonstrates basic click handling. examples/clickable/ shows a clickable region using View.OnMouse. See the Examples package page for the full list.
Related pages
- Declarative views —
MouseModeis aViewfield. - Input handling — how mouse bytes are decoded.
- Reference / messages — full message reference.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.