base on TUI components for Bubble Tea 🫧 # Bubbles <p> <img src="https://stuff.charm.sh/bubbles/bubbles-github.png" width="233" alt="The Bubbles Logo"> </p> [![Latest Release](https://img.shields.io/github/release/charmbracelet/bubbles.svg)](https://github.com/charmbracelet/bubbles/releases) [![GoDoc](https://godoc.org/github.com/golang/gddo?status.svg)](https://pkg.go.dev/github.com/charmbracelet/bubbles) [![Build Status](https://github.com/charmbracelet/bubbles/workflows/build/badge.svg)](https://github.com/charmbracelet/bubbles/actions) [![Go ReportCard](https://goreportcard.com/badge/charmbracelet/bubbles)](https://goreportcard.com/report/charmbracelet/bubbles) Some components for [Bubble Tea](https://github.com/charmbracelet/bubbletea) applications. These components are used in production in [Glow][glow], and [many other applications][otherstuff]. [glow]: https://github.com/charmbracelet/glow [otherstuff]: https://github.com/charmbracelet/bubbletea/#bubble-tea-in-the-wild ## Spinner <img src="https://stuff.charm.sh/bubbles-examples/spinner.gif" width="400" alt="Spinner Example"> 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.ā€ - [Example code, basic spinner](https://github.com/charmbracelet/bubbletea/blob/main/examples/spinner/main.go) - [Example code, various spinners](https://github.com/charmbracelet/bubbletea/blob/main/examples/spinners/main.go) ## Text Input <img src="https://stuff.charm.sh/bubbles-examples/textinput.gif" width="400" alt="Text Input Example"> 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. - [Example code, one field](https://github.com/charmbracelet/bubbletea/blob/main/examples/textinput/main.go) - [Example code, many fields](https://github.com/charmbracelet/bubbletea/blob/main/examples/textinputs/main.go) ## Text Area <img src="https://stuff.charm.sh/bubbles-examples/textarea.gif" width="400" alt="Text Area Example"> 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. - [Example code, chat input](https://github.com/charmbracelet/bubbletea/blob/main/examples/chat/main.go) - [Example code, story time input](https://github.com/charmbracelet/bubbletea/blob/main/examples/textarea/main.go) ## Table <img src="https://stuff.charm.sh/bubbles-examples/table.gif" width="400" alt="Table Example"> A component for displaying and navigating tabular data (columns and rows). Supports vertical scrolling and many customization options. - [Example code, countries and populations](https://github.com/charmbracelet/bubbletea/blob/main/examples/table/main.go) ## Progress <img src="https://stuff.charm.sh/bubbles-examples/progress.gif" width="800" alt="Progressbar Example"> A simple, customizable progress meter, with optional animation via [Harmonica][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. - [Animated example](https://github.com/charmbracelet/bubbletea/blob/main/examples/progress-animated/main.go) - [Static example](https://github.com/charmbracelet/bubbletea/blob/main/examples/progress-static/main.go) [harmonica]: https://github.com/charmbracelet/harmonica ## Paginator <img src="https://stuff.charm.sh/bubbles-examples/pagination.gif" width="200" alt="Paginator Example"> 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. - [Example code](https://github.com/charmbracelet/bubbletea/blob/main/examples/paginator/main.go) ## Viewport <img src="https://stuff.charm.sh/bubbles-examples/viewport.gif" width="600" alt="Viewport Example"> 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. - [Example code](https://github.com/charmbracelet/bubbletea/blob/main/examples/pager/main.go) This component is well complemented with [Reflow][reflow] for ANSI-aware indenting and text wrapping. [reflow]: https://github.com/muesli/reflow ## List <img src="https://stuff.charm.sh/bubbles-examples/list.gif" width="600" alt="List Example"> 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]. - [Example code, default list](https://github.com/charmbracelet/bubbletea/blob/main/examples/list-default/main.go) - [Example code, simple list](https://github.com/charmbracelet/bubbletea/blob/main/examples/list-simple/main.go) - [Example code, all features](https://github.com/charmbracelet/bubbletea/blob/main/examples/list-fancy/main.go) ## File Picker <img src="https://vhs.charm.sh/vhs-yET2HNiJNEbyqaVfYuLnY.gif" width="600" alt="File picker example"> A customizable component for picking a file from the file system. Navigate through directories and select files, optionally limit to certain file extensions. - [Example code](https://github.com/charmbracelet/bubbletea/blob/main/examples/file-picker/main.go) ## Timer A simple, flexible component for counting down. The update frequency and output can be customized as you like. <img src="https://stuff.charm.sh/bubbles-examples/timer.gif" width="400" alt="Timer example"> - [Example code](https://github.com/charmbracelet/bubbletea/blob/main/examples/timer/main.go) ## Stopwatch <img src="https://stuff.charm.sh/bubbles-examples/stopwatch.gif" width="400" alt="Stopwatch example"> A simple, flexible component for counting up. The update frequency and output can be customized as you see fit. - [Example code](https://github.com/charmbracelet/bubbletea/blob/main/examples/stopwatch/main.go) ## Help <img src="https://stuff.charm.sh/bubbles-examples/help.gif" width="500" alt="Help Example"> 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. - [Example code](https://github.com/charmbracelet/bubbletea/blob/main/examples/help/main.go) ## 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. ```go 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.KeyMsg: 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](https://github.com/charm-and-friends/additional-bubbles). Made a cool Bubble that you want to share? [PRs](https://github.com/charm-and-friends/additional-bubbles?tab=readme-ov-file#what-is-a-complete-project) are welcome! ## Contributing See [contributing][contribute]. [contribute]: https://github.com/charmbracelet/bubbles/contribute ## Feedback We’d love to hear your thoughts on this project. Feel free to drop us a note! - [Twitter](https://twitter.com/charmcli) - [The Fediverse](https://mastodon.social/@charmcli) - [Discord](https://charm.sh/chat) ## License [MIT](https://github.com/charmbracelet/bubbletea/raw/main/LICENSE) --- Part of [Charm](https://charm.sh). <a href="https://charm.sh/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-banner-next.jpg" width="400"></a> Charmēƒ­ēˆ±å¼€ęŗ • Charm loves open source ", Assign "at most 3 tags" to the expected json: {"id":"8441","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"