Simple, beautiful CLI output for Haskell.
Build declarative and composable sections, trees, tables, dashboards for your Haskell applications. . Zero dependencies, rich text formatting with alignment, underlines, padding, margins. Features lists, trees, tables, charts, banners and more.

layoutz
Simple, beautiful CLI output for Haskell ๐ชถ
Build declarative and composable sections, trees, tables, dashboards for your Haskell applications.
Features
- Zero dependencies, use
Layoutz.hslike a header file - Rich text formatting: alignment, underlines, padding, margins
- Lists, trees, tables, charts, banners...
Installation
Add to your package.yaml or .cabal file:
dependencies:
- layoutz
Or install directly:
cabal install layoutz
All you need:
import Layoutz
Quickstart
Beautiful, compositional text layouts:
import Layoutz
demo = layout
[ center $ row [text "Layoutz", underline' "ห" $ text "DEMO"]
, br
, row
[ statusCard "Users" "1.2K"
, statusCard' DoubleBorder "API" "UP"
, statusCard' ThickBorder "CPU" "23%"
, table' RoundBorder ["Name", "Role", "Status"]
[ [text "Alice", text "Engineer", text "Online"]
, [text "Eve", text "QA", text "Away"]
]
, section "Pugilists" [kv [("Kazushi", "Sakuraba"), ("Jet", "Li")]]
]
]
putStrLn $ render demo
Layoutz DEMO
หหหห
โโโโโโโโโโโ โโโโโโโโโ โโโโโโโโโ โญโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโฎ === Pugilists ===
โ Users โ โ API โ โ CPU โ โ Name โ Role โ Status โ Kazushi: Sakuraba
โ 1.2K โ โ UP โ โ 23% โ โโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโค Jet: Li
โโโโโโโโโโโ โโโโโโโโโ โโโโโโโโโ โ Alice โ Engineer โ Online โ
โ Eve โ QA โ Away โ
โฐโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโฏ
Core concepts
- Every piece of content is an
Element - Elements are immutable and composable - build complex layouts by combining simple elements
- A
layoutarranges elements vertically:
layout [elem1, elem2, elem3] -- Joins with "\n"
Call render on any element to get a string
The power comes from uniform composition - since everything has the Element typeclass, everything can be combined.
Elements
Text
text "Simple text"
Simple text
Line Break
Add line breaks with br:
layout [text "Line 1", br, text "Line 2"]
Line 1
Line 2
Section: section
section "Config" [kv [("env", "prod")]]
section' "-" "Status" [kv [("health", "ok")]]
section'' "#" "Report" 5 [kv [("items", "42")]]
=== Config ===
env: prod
--- Status ---
health: ok
##### Report #####
items: 42
Layout (vertical): layout
layout [text "First", text "Second", text "Third"]
First
Second
Third
Row (horizontal): row
row [text "Left", text "Middle", text "Right"]
Left Middle Right
Horizontal rule: hr
hr
hr' "~"
hr'' "-" 10
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
----------
Key-value pairs: kv
kv [("name", "Alice"), ("role", "admin")]
name: Alice
role: admin
Table: table
Tables automatically handle alignment and borders:
table ["Name", "Age", "City"]
[ [text "Alice", text "30", text "New York"]
, [text "Bob", text "25", text ""] -- Missing values handled
, [text "Charlie", text "35", text "London"]
]
โโโโโโโโโโโฌโโโโโโฌโโโโโโโโโโ
โ Name โ Age โ City โ
โโโโโโโโโโโผโโโโโโผโโโโโโโโโโค
โ Alice โ 30 โ New Yorkโ
โ Bob โ 25 โ โ
โ Charlie โ 35 โ London โ
โโโโโโโโโโโดโโโโโโดโโโโโโโโโโ
Unordered Lists: ul
Clean unordered lists with automatic nesting:
ul [text "Feature A", text "Feature B", text "Feature C"]
โข Feature A
โข Feature B
โข Feature C
Nested lists with auto-styling:
ul [ text "Backend"
, ul [text "API", text "Database"]
, text "Frontend"
, ul [text "Components", ul [text "Header", ul [text "Footer"]]]
]
โข Backend
โฆ API
โฆ Database
โข Frontend
โฆ Components
โช Header
โข Footer
Underline: underline
Add underlines to any element:
underline $ text "Important Title"
underline' "=" $ text "Custom"
Important Title
โโโโโโโโโโโโโโโ
Custom
โโโโโโ
Box: box
With title:
box "Summary" [kv [("total", "42")]]
โโโSummaryโโโโ
โ total: 42 โ
โโโโโโโโโโโโโโ
Without title:
box "" [kv [("total", "42")]]
โโโโโโโโโโโโโโ
โ total: 42 โ
โโโโโโโโโโโโโโ
Status card: statusCard
statusCard "CPU" "45%"
โโโโโโโโโ
โ CPU โ
โ 45% โ
โโโโโโโโโ
Progress bar: inlineBar
inlineBar "Download" 0.75
Download [โโโโโโโโโโโโโโโโโโโโ] 75%
Tree: tree
tree "Project"
[ branch "src"
[ leaf "main.hs"
, leaf "test.hs"
]
, branch "docs"
[ leaf "README.md"
]
]
Project
โโโ src
โ โโโ main.hs
โ โโโ test.hs
โโโ docs
โโโ README.md
Chart: chart
chart [("Web", 10), ("Mobile", 20), ("API", 15)]
Web โโโโโโโโโโโโโโโโโโโโโ 10
Mobile โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 20
API โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 15
Padding: pad
Add uniform padding around any element:
pad 2 $ text "content"
content
Centering: center
Smart auto-centering and manual width:
center $ text "Auto-centered" -- Uses layout context
center' 20 $ text "Manual width" -- Fixed width
Auto-centered
Manual width
Margin: margin
Use margin for colorful "compiler-style" prefixes:
layout
[ marginError [text "Type error: expected Int, got String"]
, marginWarn [text "Unused variable 'temp'"]
, marginSuccess [text "Build completed successfully"]
, marginInfo [text "Pro tip: Use layoutz for beautiful output"]
]
[error] Type error: expected Int, got String
[warn] Unused variable 'temp'
[success] Build completed successfully
[info] Pro tip: Use layoutz for beautiful output
Border Styles
Elements like box, table, and statusCard support different border styles:
NormalBorder (default):
box "Title" [text "content"]
โโโTitleโโโ
โ content โ
โโโโโโโโโโโ
DoubleBorder:
statusCard' DoubleBorder "API" "UP"
โโโโโโโโโ
โ API โ
โ UP โ
โโโโโโโโโ
ThickBorder:
table' ThickBorder ["Name"] [[text "Alice"]]
โโโโโโโโโ
โ Name โ
โฃโโโโโโโโซ
โ Alice โ
โโโโโโโโโ
RoundBorder:
box' RoundBorder "Info" [text "content"]
โญโโInfoโโโโฎ
โ content โ
โฐโโโโโโโโโโฏ
REPL Usage
Drop into GHCi to experiment:
cabal repl
ฮป> import Layoutz
ฮป> putStrLn $ render $ center $ box "Hello" [text "World!"]
โโโHelloโโโ
โ World! โ
โโโโโโโโโโโ
ฮป> putStrLn $ render $ table ["A", "B"] [[text "1", text "2"]]
โโโโโฌโโโโ
โ A โ B โ
โโโโโผโโโโค
โ 1 โ 2 โ
โโโโโดโโโโ
Inspiration
- Original Scala layoutz.