bubbles

charmbraceletMIT活跃维护

给 Bubble Tea 框架提供现成的终端界面组件库,输入框、列表、表格、进度条等开箱即用,省去自己手写 TUI 控件。

TUI components for Bubble Tea 🫧

v2.2.1发布于 2026-08-24 09:15 UTC9,039star +6 / 7 天486fork同步于 2026-11-10 11:31 UTC

怎么上手

由 README 提炼,执行前请确认
go get charm.land/bubbles/v2
硬件要求按 README 说明

README 未说明,纯 Go 终端库,无 GPU 或显存要求

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

Bubble Tea 的官方 TUI 组件库,提供开箱即用的终端界面基础组件

给 Bubble Tea 框架提供现成的终端界面组件库,输入框、列表、表格、进度条等开箱即用,省去自己手写 TUI 控件。

核心能力

  • 提供 Spinner、Text Input、Text Area、Table、Progress 等常用组件
  • List 组件内置分页、模糊过滤、自动帮助和状态消息
  • Viewport 支持垂直滚动、鼠标滚轮和备用屏幕高性能模式
  • Key 组件统一管理键位绑定并自动生成帮助视图
  • File Picker 支持目录导航和按扩展名过滤文件

容易踩的坑

从 v1 升级需先阅读 UPGRADE_GUIDE_V2.md,导入路径已改为 charm.land/bubbles/v2;组件需配合 Bubble Tea 使用,不能单独运行;示例代码位于 bubbletea 仓库而非本仓库

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v2.2.1
  1. v2.2.1最新正式版2026-08-24 · 2026-08-24 09:15 UTC

    Tiny Monday bugfix

    Textarea element had a bug, where you used to be able to go 1 word backwards, even if there was nothing, which resulted in the whole TUI freezing. It was now fixed by @OxQuasar!

    Changelog

    Fixed

    • f6134114d735cf40e95c15ff62e7359e46d04fc9: fix(textarea): stop word-left at input boundary (#1036) (@OxQuasar)

    Docs

    • 87d445838781700cb25e3fc3a6b26006eab97b41: docs: update godoc link in readme to new package (@meowgorithm)

    Other stuff

    • 10489b5fafe92bfaea873297cab8ac8b5c5237f4: readme: drop tree section for now (@meowgorithm)
    • 490948109eb4731927ba2f4cd464d8175a9630d7: v2.2.1 (@andrinoff)

    Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

  2. v2.2.02026-08-21 · 2026-08-21 08:02 UTC
    查看更新说明

    A new Bubble and some new Textarea stuff

    There are a couple nice features in today's release. Let's check em out!

    If a tree falls in the forest…

    At last, the tree Bubble from all star contributor @dlvhdr’s is here! He built it for DiffNav and graciously contributed to Bubbles. We've been working with Dolev for a long time and were totally stoked when he offerd to contribute.

    Select all, ctrl+c, ctrl+v…done!

    Our own @andrinoff added a bunch of awesome stuff to Textarea, including the long awaited text selection. Select, copy, and cut your way into mini text editing.

    For more info see the docs.

    And special thanks to @zoriya for adding ctrl+left/right bindings.

    xoxo, Charm! 💌

    Changelog

    New!

    • 8cea431500a8837c241cbe8ad71601aa8f00a0d9: feat(textarea): support ctrl + left/right/backspace (#1020) (@zoriya)
    • 037ad37bb0aa6e8ec544df6d3af752755f0a72d9: feat: textarea selection (#1029) (@andrinoff)
    • e97af08ee293131e7b71f7e3006c06a81a2584b8: feat: tree bubble (#893) (@dlvhdr)

    Fixed

    • 6484e49c0a051fe100cb16c0e184cabd4b53a6f0: fix(filepicker): don't blank the view when height is unset (#1026) (@andrinoff)

    Other stuff

    • 355f960a27f9b0bf455b3ddea66dc987db62317d: ci: sync dependabot config (#896) (@charmcli)
    • ef8af03870c1817d3b0b4fa0578b661a576e0220: v2.2.0 (@andrinoff)

    Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

  3. v2.1.12026-07-04 · 2026-07-04 11:43 UTC
    查看更新说明

    Lil’ Textarea Fix

    This is a tiny patch to fix a bug in textarea where the prompt character could be missing styling on empty lines. That’s all for now!

    Thanks for using Bubbles, Charm 🌞

    Changelog

    Fixed

    • d2b2217d6352ce04183623d66d4266115419733c: fix(textarea): apply prompt style on all lines, including fillers (@meowgorithm)

    Docs

    • a13f110fba4f13ce5fe9bc7fd51619f5782077b9: docs: fix typo in README (#921) (@Rohan5commit)

    Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

  4. v2.1.02026-03-26 · 2026-03-26 19:03 UTC
    查看更新说明

    Shrink ’n’ grow your textareas

    The update adds a new feature to automatically resize your textarea vertically as its content changes.

    ta := textarea.New()
    ta.DynamicHeight = true   // Enable dynamic resizing
    ta.MinHeight = 3          // Minimum visible rows
    ta.MaxHeight = 10         // Maximum visible rows
    ta.MaxContentHeight = 20  // Maximum rows of content
    

    Piece of cake, right?

    Enjoy! 💘

    Changelog

    New!

    • f1daacfa0cfee07e31a12498078426d275aa5286: feat(textarea): dynamic height (#910) (@meowgorithm)

    Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

  5. v2.0.02026-02-24 · 2026-02-24 15:44 UTC
    查看更新说明

    bubbles-v2-block

    Bubbles v2 is here! 🫧

    We're thrilled to share Bubbles v2 with you! This release accompanies Bubble Tea v2 and Lip Gloss v2 and brings a ton of consistency, new features, and quality-of-life improvements across every component. Catch 'em all:

    go get charm.land/bubbletea/v2
    go get charm.land/bubbles/v2
    go get charm.land/lipgloss/v2
    

    You can also check the Upgrade Guide for more info.

    There are a lot of changes in here, but we've found upgrading pretty easy, especially with a linter. Read on for the full breakdown!

    [!NOTE] When in doubt, check the examples for reference — they've all been updated for v2.

    🏠 New Home

    Bubbles v2 now lives at charm.land:

    import "charm.land/bubbles/v2"
    

    All sub-packages follow the same pattern: charm.land/bubbles/v2/viewport, charm.land/bubbles/v2/list, etc.

    🎨 Light and Dark Styles

    Some Bubbles, like help, offer default styles for both light and dark backgrounds. Since Lip Gloss v2 removes AdaptiveColor, choosing light or dark is now a manual process. You've got a couple of options.

    🎩 The Best Way

    Have Bubble Tea query the background color for you. This properly queries the correct inputs and outputs, and happens in lockstep with your application:

    func (m model) Init() tea.Cmd {
        return tea.RequestBackgroundColor
    }
    
    func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
        switch msg := msg.(type) {
        case tea.BackgroundColorMsg:
            m.help.Styles = help.DefaultStyles(msg.IsDark())
            return m, nil
        }
        // ...
    }
    

    If you're using Wish you must do it this way to get the background color of the client.

    🤠 The Quick Way

    Use the compat package in Lip Gloss. It's less recommended because it contains blocking I/O that operates independently of Bubble Tea, and when used with Wish it won't detect the client's background:

    import "charm.land/lipgloss/v2/compat"
    
    var hasDarkBG = compat.HasDarkBackground()
    
    h := help.New()
    h.Styles = help.DefaultStyles(hasDarkBG)
    

    👀 Or Just Pick One

    h.Styles = help.DefaultLightStyles() // light mode!
    h.Styles = help.DefaultDarkStyles()  // jk dark mode
    

    This pattern applies to help, list, textarea, and textinput.

    🔑 The Init You Know and Love is Back

    After experimenting with a few different forms of Init during the alphas, we decided the v1 signature was the right call after all. Init was a bit too redundant for our tastes given that initialization already happens in New:

    func (m Model) Init() tea.Cmd
    

    ✨ The Big Highlights

    Getters and Setters Everywhere

    All components now use getter/setter methods instead of exported Width and Height fields. This lets us do internal bookkeeping when things change, and it makes the API consistent across every Bubble:

    // Before
    vp.Width = 40
    fmt.Println(vp.Width)
    
    // After
    vp.SetWidth(40)
    fmt.Println(vp.Width())
    

    Affected: filepicker, help, progress, table, textinput, viewport.

    Functional Options

    Constructors now use the functional options pattern instead of positional args or separate constructor functions:

    vp := viewport.New(viewport.WithWidth(80), viewport.WithHeight(24))
    sw := stopwatch.New(stopwatch.WithInterval(500 * time.Millisecond))
    t := timer.New(30*time.Second, timer.WithInterval(100*time.Millisecond))
    

    DefaultKeyMap is a Function Now

    All DefaultKeyMap package-level variables are now functions, so you get fresh values every time:

    km := textinput.DefaultKeyMap()   // was textinput.D
    

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    Bubbles

    Latest Release GoDoc Build Status Go ReportCard

    Primitives for Bubble Tea applications. These components are used in production in Crush, and many other applications.

    [!TIP]

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

    Spinner

    A spinner, useful for indicating that some kind an operation is happening. There are a couple default ones, but you can also pass your own ”frames.”

    Text Input

    A text input field, akin to an <input type="text"> in HTML. Supports unicode, pasting, in-place scrolling when the value exceeds the width of the element and the common, and many customization options.

    Text Area

    A text area field, akin to an <textarea /> in HTML. Allows for input that spans multiple lines. Supports unicode, pasting, vertical scrolling when the value exceeds the width and height of the element, and many customization options.

    Table

    A component for displaying and navigating tabular data (columns and rows). Supports vertical scrolling and many customization options.

    Progress

    A simple, customizable progress meter, with optional animation via Harmonica. Supports solid and gradient fills. The empty and filled runes can be set to whatever you'd like. The percentage readout is customizable and can also be omitted entirely.

    Paginator

    A component for handling pagination logic and optionally drawing pagination UI. Supports "dot-style" pagination (similar to what you might see on iOS) and numeric page numbering, but you could also just use this component for the logic and visualize pagination however you like.

    Viewport

    A viewport for vertically scrolling content. Optionally includes standard pager keybindings and mouse wheel support. A high performance mode is available for applications which make use of the alternate screen buffer.

    This component is well complemented with Reflow for ANSI-aware indenting and text wrapping.

    List

    A customizable, batteries-included component for browsing a set of items. Features pagination, fuzzy filtering, auto-generated help, an activity spinner, and status messages, all of which can be enabled and disabled as needed. Extrapolated from [Glow][glow].

    File Picker

    A customizable component for picking a file from the file system. Navigate through directories and select files, optionally limit to certain file extensions.

    Timer

    A simple, flexible component for counting down. The update frequency and output can be customized as you like.

    Stopwatch

    A simple, flexible component for counting up. The update frequency and output can be customized as you see fit.

    Help

    A customizable horizontal mini help view that automatically generates itself from your keybindings. It features single and multi-line modes, which the user can optionally toggle between. It will truncate gracefully if the terminal is too wide for the content.

    Key

    A non-visual component for managing keybindings. It’s useful for allowing users to remap keybindings as well as generating help views corresponding to your keybindings.

    type KeyMap struct {
        Up key.Binding
        Down key.Binding
    }
    
    var DefaultKeyMap = KeyMap{
        Up: key.NewBinding(
            key.WithKeys("k", "up"),        // actual keybindings
            key.WithHelp("↑/k", "move up"), // corresponding help text
        ),
        Down: key.NewBinding(
            key.WithKeys("j", "down"),
            key.WithHelp("↓/j", "move down"),
        ),
    }
    
    func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
        switch msg := msg.(type) {
        case tea.KeyPressMsg:
            switch {
            case key.Matches(msg, DefaultKeyMap.Up):
                // The user pressed up
            case key.Matches(msg, DefaultKeyMap.Down):
                // The user pressed down
            }
        }
        return m, nil
    }
    

    There’s more where that came from

    To check out community-maintained Bubbles see Charm & Friends. Made a cool Bubble that 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!

    License

    MIT


    Part of Charm.

    Charm热爱开源 • Charm loves open source