jjenkins

jjenkins

Drafter - Build rich terminal UIs in Elixir, locally or over SSH

I’ve been working on a TUI framework for Elixir called Drafter, inspired by Python’s Textual but built around Elixir idioms — declarative rendering, pattern-matched event handling, and OTP-native architecture.

elixir run_examples.exs

The basic idea:

Mix.install([{:drafter, "~> 0.1.3"}])
defmodule CounterApp do
  use Drafter.App

  def mount(_props), do: %{count: 0}

  def render(state) do
    vertical([
      header("Counter"),
      label("Count: #{state.count}", flex: 1),
      horizontal([
        button("−", on_click: :dec),
        button("+", on_click: :inc)
      ], gap: 2),
      footer(bindings: [{"q", "Quit"}])
    ])
  end

  def handle_event(:inc, _data, state), do: {:ok, %{state | count: state.count + 1}}
  def handle_event(:dec, _data, state), do: {:ok, %{state | count: state.count - 1}}
  def handle_event({:key, :q}, _state), do: {:stop, :normal}
  def handle_event(_event, state), do: {:noreply, state}
end

Drafter.run(CounterApp)

What’s in the box:

  • 30+ widgets — DataTable, Tree, Charts, TextInput, TextArea, Checkbox, RadioSet, Markdown, CodeView, and more
  • Flexible layouts — vertical, horizontal, grid, scrollable, sidebar
  • Multi-screen navigation — push/pop screens, modals, popovers, panels, toasts
  • Theming system with HSL/RGB/hex color support
  • Declarative widget event handling with automatic focus management
  • DOM-like three-phase event system (capture → target → bubble)
  • Animation engine with 30+ easing functions
  • Syntax highlighting via tree-sitter (optional)
  • Headless testing harness for ExUnit
  • Many examples

TUI over SSH:

Drafter.Server.start_ssh(ChatApp,
  port: 2222,
  mode: :shared,
  auth: [{"alice", "pass"}, {"bob", "pass"}]
)

Any standard SSH client connects and gets a full interactive TUI session. :shared mode means all connected clients see the same state — input from any client updates everyone’s view in real time. The included ssh_chat.exs example is a working multi-user chat app you can try in a couple of minutes.

Built on OTP 28 — raw terminal mode, proper Unicode, and lazy input reading. Earlier OTP versions won’t work correctly.

Feedback and contributions welcome. Still early, but it’s been running real apps reliably.

drafter | Hex
Drafter — drafter v0.2.10

https://github.com/jaman/drafter

Most Liked

fuelen

fuelen

It looks interesting. I’m wondering how it differs from https://github.com/pcharbon70/term_ui ?

jjenkins

jjenkins

Thanks!

I’m hoping we see some nice Elixir/beam TUI apps, as well as any feedback for improvements, or any additions.

i will, hopefully soon, drop my heavily WIP project that rides on top of it. Grafana TUI client.
Just need to generate some sharable pics.

jjenkins

jjenkins

Thanks For pointing that out. I had gone through all of the TUI libraries I could find for Elixir (and checked other ecosystems) before starting on my own library.

I’ve taken a look at term_ui and really like a number of the widgets, and the clean simplicity. I would ask that you try out all of the examples from both projeccts. I know that Drafter is still very much a WIP, but it’s getting there.
There are a number of things we do differently, including colors, themes, animations, mouse support, etc.
I may look to borrow some of the themes/ideas of term_ui as I continue to work on Drafter.

Please let me know what you think after trying both.

Thanks.

Where Next?

Popular in Announcing Top

danschultzer
In short Plug n’ play OAuth 2.0 provider library. Just set up a resource owner schema with Ecto (your user schema), install the dependen...
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
josevalim
Hi everyone, We would like to announce that Plataformatec is working on a new MySQL driver called MyXQL. Our goal is to eventually integ...
New
brainlid
LangChain is short for Language Chain. An LLM, or Large Language Model, is the “Language” part. This library makes it easier for Elixir a...
New
bryanjos
Hi, I wanted share a small library we at Revelry Labs made for rendering react components from the server side. There are instructions fo...
New
RobertDober
Earmark is a pure-Elixir Markdown converter. It is intended to be used as a library (just call Earmark.as_html), but can also be used as...
239 12645 134
New
michalmuskala
Another small library today. PersistentEts Hex: persistent_ets | Hex GitHub: GitHub - michalmuskala/persistent_ets · GitHub Ets table ...
New
hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. https://github.com/woylie/doggo Features Unstyled Phoenix components....
New
mplatts
With HEEX released we decided to start a components library using Tailwind CSS - check it out here: Petal Components. We also have a boi...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement