@hackage lucid2.11.20250303
Clear to write, read and edit DSL for HTML
Categories
License
BSD-3-Clause
Maintainer
chrisdone@gmail.com
Links
Versions
- 2.11.20250303 Mon, 3 Mar 2025
- 2.11.20230408 Thu, 19 Sep 2024
- 2.11.1 Tue, 27 Sep 2022
- 2.11.0 Sun, 8 May 2022
- 2.10.0 Sun, 8 May 2022
- 2.9.13 Sun, 8 May 2022 Show all…
Installation
Tested Compilers
Dependencies (10)
- base >=4.8 && <4.22
- blaze-builder >=0.4.0.0
- bytestring >=0.10.6.0
- containers >=0.5.6.2
- hashable >=1.2.3.2
- mmorph >=1.0.3 Show all…
Dependents (94)
@hackage/casr-logbook-reports-html, @hackage/web-rep, @hackage/hledger, @hackage/lucid-htmx, @hackage/mmark, @hackage/tintin, Show all…
lucid

Clear to write, read and edit DSL for writing HTML
Table of Contents
Introduction
HTML terms in Lucid are written with a postfix ‘_’ to indicate data
rather than code. Some examples:
p_, class_, table_, style_
See Lucid.Html5 for a complete list of Html5 combinators.
Plain text is written using the OverloadedStrings and
ExtendedDefaultRules extensions, and is automatically escaped:
λ> "123 < 456" :: Html ()
123 < 456
Elements nest by function application:
λ> table_ (tr_ (td_ (p_ "Hello, World!"))) :: Html ()
<table><tr><td><p>Hello, World!</p></td></tr></table>
Elements are juxtaposed via monoidal append:
λ> p_ "hello" <> p_ "sup" :: Html ()
<p>hello</p><p>sup</p>
Or monadic sequencing:
λ> div_ (do p_ "hello"; p_ "sup") :: Html ()
<div><p>hello</p><p>sup</p></div>
Attributes are set by providing an argument list:
λ> p_ [class_ "brand"] "Lucid Inc" :: Html ()
<p class="brand">Lucid Inc</p>
Here is a fuller example of Lucid:
table_ [rows_ "2"]
(tr_ (do td_ [class_ "top",colspan_ "2",style_ "color:red"]
(p_ "Hello, attributes!")
td_ "yay!"))
<table rows="2">
<tr>
<td style="color:red" colspan="2" class="top">
<p>Hello, attributes!</p>
</td>
<td>yay!</td>
</tr>
</table>
Rendering
For proper rendering you can easily run some HTML immediately with:
λ> renderText (p_ "Hello!")
"<p>Hello!</p>"
Or to bytes:
λ> renderBS (p_ [style_ "color:red"] "Hello!")
"<p style=\"color:red\">Hello!</p>"
For ease of use in GHCi, there is a Show instance, as
demonstrated above.
If the above rendering functions aren't suited for your purpose, you
can run the monad directly via execHtml and use the more low-level
blaze Builder, which has a plethora of output modes in
Blaze.ByteString.Builder.
See the documentation for the Lucid module for information about
using it as a monad transformer.
Good to know
- Attributes are escaped, so you cannot write arbitrary JavaScript in attributes. Instead, do something like
onclick_ "foo()". - Attributes are rendered in the order that they are written in your Haskell code.
Transforming
You can use lift to call parent monads.
λ> runReader (renderTextT (html_ (body_ (do name <- lift ask
p_ [class_ "name"] (toHtml name)))))
("Chris" :: String)
"<html><body><p class=\"name\">Chris</p></body></html>"