Liking cljdoc? Tell your friends :D

fulcro-tui

fulcro tui CI

A terminal (TUI) rendering target for Fulcro, backed by JLine.

Fulcro has always been full-stack CLJC in all ways (rendering and server processing alike). To date the server support for "rendering" has largely been useful for headless testing, but all the machinery for more was always present.

This library (finally) provides an alternative rendering target: The terminal!

it lays out a tree of terminal-native nodes (boxes, text, inputs, buttons) and paints them into a character-cell buffer that is displayed in a real terminal via JLine. Components are written with Fulcro’s standard defsc macro (their render simply returns a tree of terminal nodes) and driven by the same Fulcro data-management primitives (mutations, normalized state, transactions).

The result is a Fulcro/React-like experience with a terminal UI.

Babashka support made possible by the inclusion of JLine!

New here? Read the Fulcro TUI Guide. It is the complete reference — getting started, the element catalog, layout, focus/keyboard, modals & pickers, the application lifecycle, performance measurement, and headless testing. This README is just a quick tour; the Guide covers everything in depth.

Status

Clone the report and run the demo under babashka with bb run tui — see bb.edn for details.

API stable at 1.0.0-RC1. Everything is pretty well-tested on the rendering front, and fast (60fps on my m1 mac). The Fulcro patterns have been stable for years, but the new bb support of Fulcro is not widely tested, so expect that if you use something we haven’t tried yet, it may not work.

Adding as a dependency

Released to Clojars — use the version shown in the badge above (deps.edn):

{:deps {com.fulcrologic/fulcro-tui {:mvn/version "RELEASE"}}}

Try the demo

Run the example two-field form in a real terminal, on the JVM:

clojure -M:tui -m tui-example.form

…or under babashka (faster startup, no JVM):

bb run tui

Controls:

  • Tab / Shift-Tab move focus through the fields, the multiline notes box, the Save button, and into the item list.

  • Arrow keys move the caret (in the notes box, Up/Down move by visual line).

  • Type to edit the focused field.

  • In the multiline notes box, Enter inserts a newline (it does not submit); the box wraps to its width and self-scrolls to keep the caret visible.

  • Enter / Space activates the focused Save button or list item.

  • PageUp / PageDown scroll the item list; tabbing into the list auto-scrolls to keep the focused item visible.

  • Pick a fruit opens a modal list picker (see below): Up / Down move the highlight, Enter chooses, Escape cancels.

  • Ctrl-Q quits.

To profile the render/I/O pipeline, launch with the fulcro.tui.perf system property set (bb -Dfulcro.tui.perf=1 tui or clojure -J-Dfulcro.tui.perf=1 -M:tui); the session is profiled and a self-time report prints after you quit. See the Guide's Measuring performance section.

Overlays: modal and picker

A tui/modal node is an overlay window that floats over the rest of the UI. The driver composites it on top of the base tree and traps focus and keyboard input to it while it is open, so the controls behind it are inert. It is declarative — its presence is just app state, via an :open? flag:

(tui/modal {:id :confirm :open? confirm-open?
            :width 30 :height 7 :title "Confirm"
            :on-dismiss #(tui/transact! this [(close-confirm)])} ; Escape calls this
  (tui/text {} "Delete everything?")
  (tui/button {:id :yes :on-activate #(tui/transact! this [(do-delete)])} " Yes "))

The library owns no lifecycle: you toggle :open? (and record any result) with your own mutations, exactly as the rest of a Fulcro app works. :width/:height accept a cell count or [:fraction f]; :align (default :center) positions the window; :border? defaults to true; :on-dismiss is called on Escape.

tui/picker is a list picker built on modal — a scrollable :viewport of selectable rows where the focused row is the highlight (Up/Down move it, the list scrolls to follow, Enter selects, Escape cancels):

(tui/picker {:id        :fruit
             :open?     picker-open?
             :title     "Pick a fruit"
             :width     24 :height 8
             :options   [{:value :apple :label "Apple"}
                         {:value :pear  :label "Pear"}]
             :on-select (fn [v] (tui/transact! this [(choose-fruit {:v v})]))
             :on-cancel (fn []  (tui/transact! this [(close-picker)]))})

See the demo source in this repository for more examples, and the Fulcro TUI Guide for full coverage of elements, layout, focus/keyboard, overlays, the application lifecycle, and headless testing.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close