Clear to write, read and edit DSL for HTML.
Clear to write, read and edit DSL for HTML.
Names are consistent, and do not conflict with base or are keywords (all have suffix
_
)Same combinator can be used for attributes and elements (e.g.
style_
)For more, read the blog post
See the Lucid
module for more documentation.
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>"