reflex-vty 1.0: Terminal UIs with Haskell and Functional Reactive Programming
Obsidian is pleased to announce the 1.0 release of reflex-vty, a terminal UI framework for building interactive Haskell applications using functional reactive programming. It brings the declarative, compositional style of Reflex FRP to the practical work of building reliable terminal interfaces.
Built in Haskell using Reflex FRP, reflex-vty provides both a Reflex host and a widget library for terminal user interfaces, including layout, focus management, text input, mouse support, scrolling, styling, theming, and terminal runtime support.
reflex-vty is representative of the work of Obsidian Labs: turning ideas from advanced programming, type systems, and declarative systems design into production-quality tools that developers can use directly.
Why FRP? Functional reactive programming is a way to describe systems whose values change over time. Instead of scattering callbacks and mutable update logic throughout a program, FRP lets developers express local relationships between events and time-varying values, then compose those relationships into larger behavior. That is a powerful fit for user interfaces, where almost everything is interconnected and almost everything changes.
That reflects a broader conviction behind much of Obsidian's open-source work. Interactive programs are full of values that change over time and events that occur in response to user input, timers, network activity, external processes, and internal state transitions. The goal is not only to make those systems work, but to make their behavior legible: state has explicit dependencies, inputs are modeled as events, and the program describes how the current interface follows from the current state of the world.
That model is especially appealing for terminal applications. A TUI is small enough to make the mechanics visible, but rich enough to expose the hard problems: layout, focus, cursor state, mouse events, text entry, scrolling, rendering, and terminal capabilities all interact. reflex-vty exists to make those interactions easier to express and reason about.
Haskell is central to that goal. Its type system, purity, abstraction mechanisms, and emphasis on compositional design make it a natural language for expressing FRP programs. For reflex-vty, Haskell is more than an incidental implementation technology, it is part of the programming model itself, giving developers a precise and compositional language for building interactive systems.
Since its early releases, reflex-vty has grown from a small library into a mature framework for building TUI applications.
Text

Getting text entry right was one of the first hard problems in reflex-vty. The library introduced a TextZipper data structure to make editing manageable, but that was only the beginning.
Terminal text is more complicated than it first appears. Cursor movement, wrapping, alignment, empty lines, character widths, text transformations, and double-width Unicode characters all interact. It is easy to get these details almost right, and then discover a case where the cursor is one cell off, a line wraps incorrectly, or a wide character breaks the layout.
This is exactly the sort of problem where Haskell is valuable. The code needs to represent a precise model of text, cursor position, display width, and editing state. A good data structure, paired with types that make invalid states harder to express, turns a pile of edge cases into something that can be reasoned about locally.
Much of the project's development has gone into making text input and rendering behave correctly across those cases.
Layout

Early versions of reflex-vty relied more heavily on manually positioned widgets. That was workable for small examples, but it quickly became cumbersome.
Several approaches were considered, including constraint-based layout systems, before the project settled on the tile/grout layout and focus model. That provided a vocabulary for composing larger interfaces out of smaller widgets without forcing application authors to manually track positions.
This was also an important FRP design problem. Layout is more than just geometry: it is a set of relationships that change as terminal size, widget contents, focus state, and user input change. reflex-vty lets application code describe those relationships declaratively.
Once that model was in place, rows, columns, tiles, focus traversal, nested layouts, and input filtering became much easier to express. This was one of the major steps toward making reflex-vty feel like a framework rather than a collection of widgets.
Scrolling

Scrolling also grew from a small feature into a more general system.
The project started with scrollable text, then generalized it to scrollable widgets. From there came programmatic scrolling, automatic scroll-to-bottom behavior for chat- or log-style interfaces, and visual scrollbars.
This is a recurring theme in the project: a specific widget feature often forced a more general abstraction to become clear. In an FRP setting, the goal is not merely to implement the feature, but to expose the right signals, events, and behaviors so the feature composes cleanly with the rest of the application.
From Useful to Polished
For a while, reflex-vty was enough to build functional and useful terminal programs. One of the most interesting projects from that period was tinytools, a TUI diagram editor built with reflex-vty. Its author later became a maintainer and contributed substantially to Unicode handling, layout, rendering improvements, and bug fixes.
reflex-vty began as a small project started by two Obsidian engineers, and over time became something other people could build on, stress test, and improve.
More recently, the project turned toward the features that make terminal applications feel friendlier and more polished.
The maintainers looked at mature TUI frameworks in other ecosystems, including Bubble Tea in Go. Its Elm-inspired architecture made it feel like a distant cousin to reflex-vty, and helped inform some of the thinking around what a pleasant terminal UI framework should provide.
Styling and Theming

One of the biggest deficiencies in earlier versions of reflex-vty was styling.
For 1.0, the project added a Style module inspired by Lip Gloss, with support for borders, padding, margins, alignment, colors, text attributes, gradients, and helpers for composing images. It also added a structured theme system with presets, along with color-profile detection and downsampling for terminals with different capabilities.
This required deeper support for terminal color handling, including the differences between true color, 256-color, 16-color, ASCII, and non-TTY environments.
The result is that reflex-vty applications can now be much more visually expressive while still adapting to the terminal they are running in.
Runtime Improvements
The runtime also received substantial attention.
reflex-vty now supports alternate screen mode, cursor control, bracketed paste, terminal focus tracking, resize debouncing, and POSIX signal handling. The host also now uses a bounded event queue with backpressure, fixing a space leak that could occur when external events were produced faster than the host could consume them.
These are the kinds of details that are easy to overlook in a simple demo, but matter a great deal when building terminal applications people actually use. They are also places where the FRP model has to meet real operating-system and terminal behavior carefully. The abstractions only matter if they survive contact with production use.
Obsidian Labs
reflex-vty is a terminal UI library, but it is also an example of the kind of programming Obsidian Labs exists to advance: using strong abstractions as practical tools for building systems that are easier to build, understand, maintain, and extend.
Terminal interfaces are a good test case for that philosophy. They are constrained, stateful, event-driven, and full of edge cases. reflex-vty shows how Haskell and FRP can make those interactions explicit, compositional, and tractable.
Thank You
Thank you to everyone who contributed to the project along the way, and to Jonathan Daugherty for Graphics.Vty, without which this work would not have been possible.
reflex-vty sits at the intersection of Haskell, functional reactive programming, open-source infrastructure, and practical developer tools. Obsidian is proud to help maintain it, and looks forward to seeing what people build with it.