Terminal UI library with rich, interactive widgets — written in Golang


Rich Interactive Widgets for Terminal UIs

PkgGoDev Go Report

This Go package provides commonly needed components for terminal based user interfaces.


Among these components are:

  • Input forms (include input/password fields, drop-down selections, checkboxes, and buttons)
  • Navigable multi-color text views
  • Sophisticated navigable table views
  • Flexible tree views
  • Selectable lists
  • Grid, Flexbox and page layouts
  • Modal message windows
  • An application wrapper

They come with lots of customization options and can be easily extended to fit your needs.


go get github.com/rivo/tview

Hello World

This basic example creates a box titled "Hello, World!" and displays it in your terminal:

package main

import (

func main() {
	box := tview.NewBox().SetBorder(true).SetTitle("Hello, world!")
	if err := tview.NewApplication().SetRoot(box, true).Run(); err != nil {

Check out the GitHub Wiki for more examples along with screenshots. Or try the examples in the "demos" subdirectory.

For a presentation highlighting this package, compile and run the program found in the "demos/presentation" subdirectory.

Projects using tview


Refer to https://pkg.go.dev/github.com/rivo/tview for the package's documentation. Also check out the Wiki.


This package is based on github.com/gdamore/tcell (and its dependencies) as well as on github.com/rivo/uniseg.

Versioning and Backwards-Compatibility

I try really hard to keep this project backwards compatible. Your software should not break when you upgrade tview. But this also means that some of its shortcomings that were present in the initial versions will remain. In addition, at least for the time being, you won't find any version tags in this repo. The newest version should be the one to upgrade to. It has all the bugfixes and latest features. Having said that, backwards compatibility may still break when:

  • a new version of an imported package (most likely tcell) changes in such a way that forces me to make changes in tview as well,
  • I fix something that I consider a bug, rather than a feature, something that does not work as originally intended,
  • I make changes to "internal" interfaces such as Primitive. You shouldn't need these interfaces unless you're writing your own primitives for tview. (Yes, I realize these are public interfaces. This has advantages as well as disadvantages. For the time being, it is what it is.)

Your Feedback

Add your issue here on GitHub. Feel free to get in touch if you have any questions.

  • virtual Table view #question

    virtual Table view #question

    Does the library support virtual table?

    I'd like to build a simple log viewer with this lib, but the log is quite huge, so I don't think I'd like to load the whole logfile to memory.

    opened by pihentagy 31
  • panic: tview.(*Table).Draw.func1

    panic: tview.(*Table).Draw.func1

    I am getting a panic in tview. It looks like it might be in table.go line 469, but it is really hard to troubleshoot because of the way the panic is being printed.


    (Click image for bigger view)

    opened by joegrasse 28
  • Mouse support

    Mouse support

    Hi, this pull request adds mouse support. Here are some notes on the changes:

    • app.EnableMouse() is needed in order to enable the mouse. Mouse enabled does cause extra traffic and redrawing. Because it's disabled by default, there should be no behavior impact to existing programs.
    • Mouse enabled prevents normal selecting text in most terminals. Workaround is to use the shift key while selecting. It's the developer's decision if they want to impose this on their users.
    • Buttons, checkboxes and list items can be clicked.
    • InputField sets focus on click, it could potentially also allow you to click to a specific character position.
    • DropDown list responds to clicks, and clicking outside closes the list.
    • Clicks on TreeView and Table not implemented yet.
    • Primitives could have a new hover draw state, such as changing the background color on hover. Needs color/theming decision. (I experimented with focusing on hover, it works well but I'm not sure it's a good default)
    • Try the the presentation demo to test the mouse. You can't click to switch slides, that would be nice.

    Relevant issues: #13 #361 #338 #337

    opened by millerlogic 26
  • TextView: limiting the maximum number of lines

    TextView: limiting the maximum number of lines


    I am using TextView to display scrolling log output, but as soon as the text in the buffer becomes very big, CPU usage shoots up.

    I propose solving it by adding a new SetMaxLines() method that makes sure the buffer slice never contains more lines than the set maximum. By default, it is set to infinite, therefore this would be a backward-compatible change.

    Proposed PR: #452

    opened by jpeletier 23
  • Install error - cannot convert b.borderAttributes

    Install error - cannot convert b.borderAttributes

    go get fails with following error

    go get github.com/rivo/tview
    # github.com/rivo/tview
    Workspace/go/src/github.com/rivo/tview/box.go:343:63: cannot convert b.borderAttributes (type tcell.AttrMask) to type tcell.Style
    Workspace/go/src/github.com/rivo/tview/table.go:331:108: cannot convert attributes (type tcell.AttrMask) to type tcell.Style
    Workspace/go/src/github.com/rivo/tview/table.go:888:150: cannot convert cell.Attributes (type tcell.AttrMask) to type tcell.Style
    Workspace/go/src/github.com/rivo/tview/table.go:957:63: cannot convert a (type tcell.AttrMask) to type tcell.Style
    Workspace/go/src/github.com/rivo/tview/table.go:1020:24: invalid operation: t.selectedStyle != 0 (mismatched types tcell.Style and int)
    opened by m-ivanov 19
  • Feature: popup/docked menu

    Feature: popup/docked menu

    The reason I am asking for popup menu is that the list using as menu taking too much space if laid vertically, it just doesn't look proper as a habit if laid horizontally.

    Two solutions:

    • A
    1. Introduce a modal window, allow this modal window to be used as container, similar like flex. So user can add the list into it.
    2. Allow a triggering key(eg: m for menu) from current focused gui component, eg: page/table/textview etc to trigger the popup modal
    3. In this use case, user trigger 2 keys: m -> f to trigger a function call

    I tried current modal, it seems the way of using it is too much mind twisted. I don't like it for a few reasons:

    1. User need to put it into a page, then hide it, you will have to switch to that page in order to show it. This way, the whole page of modal normally hide the view of your working page. It is not a popup, at least the way using it does not feel intuitive

    2. This modal page is taking a tab page and it is not naturally belongs to the tab pages. If I need one modal window as menu for a tab page for some operations, there would be too many pages used for the modal windows. To avoid displaying the modal window page, when I render the tab number and switch logic, I will have to put special logic for it

    • B

    Not sure if this is good. But if it's doable and easy to implement, then it should be cool

    1. Allow a triggering key(eg: m for menu) from current focused gui component, eg: page/table/textview etc to trigger the popup modal

    2. For a tab page structured as: flex [(hidden list) | table]. The hidden list won't be showing and take any space. Only when the triggering key is pressed, then the list will be showing and take the space, the table component will take the space as normal. After user select the list item to trigger required function, the list will be hidden again.

    Just a thought for your consideration. tview will get better and even cooler :)

    opened by stephencheng 19
  • Forms can grow beyond terminal dimensions

    Forms can grow beyond terminal dimensions

    If you add too many form items to a form, it can vertically grow beyond the terminal's height. It would be nice if one could scroll within a form in such a case.

    opened by joegrasse 19
  • please publish a release

    please publish a release

    It's crucial for some (including me) to freeze their dependencies. I have my way around by running

    go get github.com/rivo/[email protected] 

    still, please publish a release



    opened by jossef 18
  • Example of popup Modal by shortcut

    Example of popup Modal by shortcut

    https://github.com/rivo/tview/wiki/Modal example list modal hardwired to root or Pages elements. But I already have List as my root element, and I want to show modal (without buttons) when I press i and close it on Esc or clicking outside. Would be nice to have an example that demonstrates how that's possible.

    The straightforward approach I tried that doesn't work.

            // Create UI elements
            list := tview.NewList()
            // Set Box properties on the List component
            list.SetBorder(true).SetTitle(" package updates ")
            // Set List properties
            infobox := tview.NewModal().
                    AddButtons([]string{"Quit", "Cancel"}).
                    SetText("Lorem Ipsum Is A Pain")
            // Attach elements and start UI app
            app := tview.NewApplication()
            app.SetRoot(list, true) // SetRoot(root Primitive, fullscreen bool)
            app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
                    if event.Key() == tcell.KeyESC {
                    // Key is a character
                    if event.Key() == tcell.KeyRune {
                            if event.Rune() == 'q' {
                            if event.Rune() == 'i' {
                    return event

    After pressing i the List border becomes single line, and it stops responding to events. Nothing else is shown. Pressing Esc doesn't revert to previous state, but exits the application.

    opened by abitrolly 17
  • Freeze and Crash

    Freeze and Crash


    New ability to send redraw request to app is cool, but adding second event loop is not.

    Crush App crush on exit. Just Ctrl-C and we see panic trace. It happened because screen is gone in Stop(), but event queue still have tcell.EventResize.

    Freeze Let take Box example and change it a bit:

    // Demo code for the Box primitive.
    package main
    import (
    func main() {
    	box := tview.NewBox().
    		SetTitle("A title")
    	app.SetInputCapture(func (event *tcell.EventKey) *tcell.EventKey {
    		switch event.Key() {
    			case tcell.KeyCtrlC:
    			case tcell.KeyCtrlQ:
    				return event
    		return nil
    	if err := app.SetRoot(box, true).Run(); err != nil {

    As you can see, I add input handler on app level. It just eat Ctrl-C and allow quit on Ctrl-Q. Build, run. Ctrl-C - and we going to endless loop somewhere around EventLoop: label Exit by Ctrl-Q working as expected, but it strange: on my more complex app any call of Application.Stop() cause panic.

    Why adding more complicated mechanism if there is already simple, reliable and extendable tcell.PostEvent()?

    opened by aunoor 16
  • Crash in program due to deadlock

    Crash in program due to deadlock

    This example program crashes when doing a CTR-C.

    fatal error: all goroutines are asleep - deadlock!
    goroutine 1 [select]:
    github.com/rivo/tview.(*Application).Run(0xc00017c000, 0x0, 0x0)
            C:/Users/user/Documents/gowork/pkg/mod/github.com/rivo/[email protected]/application.go:302 +0x205
            C:/Users/user/Documents/gowork/src/github.com/user/box/main.go:17 +0x1e5
    goroutine 19 [select]:
    github.com/gdamore/tcell/v2.(*cScreen).PollEvent(0xc00017e000, 0xc000049fa0, 0xc0002b85e0)
            C:/Users/user/Documents/gowork/pkg/mod/github.com/gdamore/tcell/[email protected]/console_win.go:372 +0xbf
    github.com/rivo/tview.(*Application).Run.func2(0xc0000b1690, 0xc00017c000)
            C:/Users/user/Documents/gowork/pkg/mod/github.com/rivo/[email protected]/application.go:267 +0xac
    created by github.com/rivo/tview.(*Application).Run
            C:/Users/user/Documents/gowork/pkg/mod/github.com/rivo/[email protected]/application.go:254 +0x11d


    // Demo code for the Box primitive.
    package main
    import (
    func main() {
    	box := tview.NewBox().
    		SetBorderPadding(0, 0, 0, 0).
    	if err := tview.NewApplication().SetRoot(box, true).Run(); err != nil {


    module github.com/joegrasse/box
    go 1.15
    require (
    	github.com/gdamore/tcell/v2 v2.2.0
    	github.com/rivo/tview v0.0.0-20210217110421-8a8f78a6dd01


    github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
    github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
    github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
    github.com/gdamore/tcell/v2 v2.0.1-0.20201017141208-acf90d56d591/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
    github.com/gdamore/tcell/v2 v2.2.0 h1:vSyEgKwraXPSOkvCk7IwOSyX+Pv3V2cV9CikJMXg4U4=
    github.com/gdamore/tcell/v2 v2.2.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
    github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
    github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
    github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
    github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
    github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
    github.com/rivo/tview v0.0.0-20210217110421-8a8f78a6dd01 h1:rtCzDXdaqhiRakJsz0bUj+3sOUjw82bJDcJrAzQ0u+M=
    github.com/rivo/tview v0.0.0-20210217110421-8a8f78a6dd01/go.mod h1:n2q/ydglZJ1kqxiNrnYO+FaX1H14vA0wKyIo953QakU=
    github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
    github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
    github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
    golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
    golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
    golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY=
    golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
    golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
    golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
    golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
    golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
    golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
    golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
    opened by joegrasse 14
  • Feature request: floating window/modal

    Feature request: floating window/modal

    Currently, a widget is set as root using (*tview.Application).SetRoot method and the current root widget can be changed can be using the same method. Only a single widget can be root at once, widgets like Flex and Grid allow users to layout widgets into a single widget and set it as root to display multiple widgets. However, there is no such widget that can "float" above the root widget and still display the content of the root widget as is.

    opened by golangdojo99 3
  • Hyperlinks


    Looks like tview does not support terminal hyperlinks; tcell added support for them in April. TextView widget should have support for them. Since the tcell.Style struct has the Url method, it would be better to somehow expose tcell.Style directly instead of using "color tags", that way decomposition of color tags can also be completely skipped and the tcell.Style struct can be used directly.

    Issue: https://github.com/gdamore/tcell/issues/300 Commit: https://github.com/gdamore/tcell/commit/e7b14a71dc78721c0f007fd6197262c52c1d4df9 Related: https://github.com/rivo/tview/issues/611

    opened by golangdojo99 0
  • Initialise Screen if SetScreen called before Run

    Initialise Screen if SetScreen called before Run


    The bug came from the a.screen == nil check in Application.SetScreen skipping the a.screenReplacement channel and just setting a.screen directly. This skipped the code following screen = <-a.screenReplacement meaning the new screen never got initialised.

    I'm not sure if the correct fix is to init the screen if a.screen == nil as I've done in this PR, or whether it would be better to pass the new screen into the screen channel whether or not there is already a screen present.

    opened by tjhowse 0
  • A screen passed via Application.SetScreen() before Application.Run() is not initialised.

    A screen passed via Application.SetScreen() before Application.Run() is not initialised.

    func withWebsocketTty(initScreen bool) {
    	// Make a WebsocketTty object
    	tty := websockettty.WebsocketTty{}
    	// Look up a terminfo definition should work
    	ti, err := tcell.LookupTerminfo("tmux")
    	if err != nil {
    	// Build a tcell.Screen object
    	screen, err := tcell.NewTerminfoScreenFromTtyTerminfo(&tty, ti)
    	if err != nil {
    	if initScreen {
    	// if !screen.CanDisplay('=', false) {
    	// 	log.Fatal("Your terminal cannot display the equals sign")
    	// }
    	// Build a tview application
    	app := tview.NewApplication()
    	box := tview.NewBox().SetBorder(true).SetTitle("Hi")
    	app.SetRoot(box, true)
    	// Start the application running in the background.
    	go app.Run()
    	// Crudely give it some time to draw.
    	time.Sleep(time.Millisecond * 100)
    	fmt.Printf("%s", tty.Screenbuffer)

    This function only prints the expected output if initScreen is true. The docs on SetScreen says Init() need not be called on a screen before passing it to the app: https://github.com/rivo/tview/blob/master/application.go#L172

    I will raise a PR shortly.

    opened by tjhowse 0
  • Using unicode in tview.List item cause rendering bug on Windows Terminal and VSCode Terminal

    Using unicode in tview.List item cause rendering bug on Windows Terminal and VSCode Terminal

    I try to use unicode text (here is japanese) in tview.List with list.AddItem(text, "", 0, func(){}), but when I scroll up or down list, some unwanted character is also rendered.

    Here is the code:

    package main
    import (
    func main() {
    	app := tview.NewApplication()
    	list := tview.NewList()
    	for i := 0; i < 20; i++ {
    		list.AddItem("abcdefghijklmnあ                                    ", "", 0, func() {})
    		list.AddItem("abcdefghあい                                        ", "", 0, func() {})
    		list.AddItem("abcdefghijあいう                                     ", "", 0, func() {})
    		list.AddItem("abcdeあいうえ                                         ", "", 0, func() {})
    		list.AddItem("abcdefghiあいうえお                                    ", "", 0, func() {})
    	app.SetRoot(list, true).Run()

    And result in Windows Terminal, it works well before I scroll down to the end, and scroll up: tview

    VSCode Terminal: tview_vscode

    It seems this bug will trigger if:

    1. Text begins with english characters.
    2. Different line has different length leading english characters.
    3. There is some space characters at the tail of text.
    opened by Chronyaa 2
  • Allow overriding border runes per instance of Box

    Allow overriding border runes per instance of Box

    Borders of focused elements are drawn differently than for unfocused ones (thicker / double lines).

    Would be nice if there is a method to control that behavior. While it's possible to override the runes that are used for focused elements globally, one might want to have this for specific boxes/containers only.

    The only way to work around it is to use SetDrawFunc and draw the borders yourself I guess?

    ~~I'm thinking about a boolean like borderIgnoreFocus added to the Box struct with a method SetBorderIgnoreFocus(ignore bool) which can then be checked in the DrawForSubclass~~


    opened by moson-mo 4
A rich tool for parsing flags and values in pure Golang

A rich tool for parsing flags and values in pure Golang. No additional library is required and you can use everywhere.

ALi.w 14 Jan 25, 2022
Secure, private and feature-rich CLI password manager

Kure Kure is a free and open-source password manager for the command-line. This project aims to offer the most secure and private way of operating wit

Gastón Palomeque 125 Aug 23, 2022
A golang library for building interactive prompts with full support for windows and posix terminals.

Survey A library for building interactive prompts on terminals supporting ANSI escape sequences. package main import ( "fmt" "github.com/Alec

Alec Aivazis 3.3k Oct 1, 2022
Stonks is a terminal based stock visualizer and tracker that displays realtime stocks in graph format in a terminal.

Stonks is a terminal based stock visualizer and tracker. Installation Requirements: golang >= 1.13 Manual Clone the repo Run make && make install Pack

Eric Moynihan 514 Sep 18, 2022
Abacus is a simple interactive calculator CLI

Abacus is a simple interactive calculator CLI with support for variables, comparison checks, and math functions abacus -

Viktor Danov 33 Sep 15, 2022
🔥 [WIP] Interactive Jira Command Line

JiraCLI Interactive Jira CLI ?? This project is still a work in progress ?? This tool mostly focuses on issue search and navigation at the moment. How

Ankit Pokhrel 2.1k Sep 30, 2022
Building powerful interactive prompts in Go, inspired by python-prompt-toolkit.

go-prompt A library for building powerful interactive prompts inspired by python-prompt-toolkit, making it easier to build cross-platform command line

Masashi Shibata 4.6k Sep 26, 2022
Simplistic interactive filtering tool

peco Simplistic interactive filtering tool NOTE: If you are viewing this on GitHub, this document refers to the state of peco in whatever current bran

null 7.1k Oct 2, 2022
Interactive prompt for command-line applications

promptui Interactive prompt for command-line applications. We built Promptui because we wanted to make it easy and fun to explore cloud services with

Manifold 5.1k Sep 29, 2022
Build an interactive CLI application with Go, Cobra and promptui. Video tutorial available on the Div Rhino YouTube channel.

Build an interactive CLI app with Go, Cobra and promptui Text tutorial: https://divrhino.com/articles/build-interactive-cli-app-with-go-cobra-promptui

Div Rhino Dev 15 Sep 17, 2022
Interactive CLI helper for creating git branches with JIRA Links and some text

bb (better-branch) Interactive CLI helper for creating git branches with JIRA Links and some text Still in development? Yes How it works? This tiny ut

Eugene Uvarov 3 Aug 18, 2022
Interactive cli tool for HTTP inspection

Wuzz command line arguments are similar to cURL's arguments, so it can be used to inspect/modify requests copied from the browser's network inspector with the "copy as cURL" feature.

Adam Tauber 10.1k Sep 27, 2022
Interactive prompt to set and push a semver tag

cutver For when you know what version to tag, and you want to cut a release in the annotated tag format. Installation go install github.com/roryq/cutv

Rory Quinn 7 Oct 11, 2021
An interactive command-line tool to manage your environments

goto An interactive command-line tool to manage your environments Overview You always need to login to some Linux machine or connect to a MySQL instan

Lucien 10 Jul 11, 2022
This tool is a CLI-interactive tool for TA who use eeclass platform

NTHU eeclass TA helper. This tool is a CLI-interactive tool for TA who use eeclass platform. It helps TA to download all the submitted homework, and use CSV to record the score and comment, and upload CSV score directly to the eeclass platform with just 2 Enter key!

Bo-Wei Chen 1 Dec 11, 2021
🧨 Interactive Process Killer CLI made with Go!

proc-manager is an interactive CLI to kill processes made with Go, currently supports Linux, Mac OS X, Solaris, and Windows.

Aykut 21 Sep 19, 2022
Generate an interactive, autocompleting shell for any Cobra CLI

cobra-shell Description Leverages the Cobra completion API to generate an interactive shell for any Cobra CLI, powered by go-prompt. On-the-fly autoco

Brian Strauch 29 Aug 31, 2022
The missing git branch --interactive

git branch-i I got cross that there's no git branch --interactive, so I made this. It's a very (very) simple curses-mode git branch/git checkout alter

Joel Auterson 3 Dec 17, 2021
An interactive shell for go application

goshell An interactive shell for go application in normal mode ctrl-c break exec

null 1 Aug 4, 2022