package dream-html
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=655ea78590ded1978dca7b5a14690635d067a0295787ab099144b8c4b4b9e954
sha512=87dbbb5b8ad0351f481e904829676a3f43504b5b6c83683a40cf43e45ed4a0465012aada6b7008677c8634ea51038e91e2b99d535b6efc9dd9b9859e8a28703c
Description
Write HTML directly in your OCaml source files with editor support.
Published: 12 Dec 2023
README
dream-html - generate HTML markup from your Dream backend server
Copyright 2023 Yawar Amin
This file is part of dream-html.
dream-html is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
dream-html is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with dream-html. If not, see https://www.gnu.org/licenses/.
What
An HTML library that is closely integrated with Dream. Most HTML elements and attributes from the Mozilla Developer Network references are now implemented. I have deliberately left out almost all non-standard or deprecated tags/attributes. Also, supporting CSS is out of scope for this library. However, I have included the htmx attributes as I am personally using them.
Why
TyXML is a bit too complex.
Dream's built-in eml (Embedded ML) has some drawbacks like no editor support, quirky syntax that can be hard to debug, and manual dune rule setup for each view file. Also in general string-based HTML templating is suboptimal.
First look
let page req =
let open Dream_html in
let open HTML in
html [lang "en"] [
head [] [
title [] "Dream-html" ];
body [] [
h1 [] [txt "Dream-html"];
p [] [txt "Is cool!"];
form [method_ `POST; action "/feedback"] [
(* Integrated with Dream's CSRF token generation *)
csrf_tag req;
label [for_ "what-you-think"] [txt "Tell us what you think!"];
input [name "what-you-think"; id "what-you-think"];
input [type_ "submit"; value "Send"] ] ] ]
(* Integrated with Dream response *)
let handler req = Dream_html.respond (page req)
Security (HTML escaping)
Attribute and text values are escaped using rules very similar to standards- compliant web browsers:
utop # open Dream_html;;
utop # open HTML;;
utop # #install_printer pp;;
utop # let user_input = "<script>alert('You have been pwned')</script>";;
val user_input : string = "<script>alert('You have been pwned')</script>"
utop # p [] [txt "%s" user_input];;
- : node = <p><script>alert('You have been pwned')</script></p>
utop # div [title_ {|"%s|} user_input] [];;
- : node = <div title=""<script>alert('You have been pwned')</script>"></div>
How to install
Make sure your local copy of the opam repository is up-to-date first:
opam update
opam install dream-html
Usage
A convenience is provided to respond with an HTML node from a handler:
Dream_html.respond greeting
You can compose multiple HTML nodes together into a single node without an extra DOM node, like React fragments:
let view = null [p [] [txt "Hello"]; p [] [txt "World"]]
You can do string interpolation using the txt
node constructor and of any attribute which takes a string value:
let greet name = p [id "greet-%s" name] [txt "Hello, %s!" name]
You can conditionally render an attribute, and void elements are statically enforced as childless:
let entry =
input
[ (if should_focus then autofocus else null_);
id "email";
name "email";
value "Email address" ]
You can also embed HTML comments in the generated document:
div [] [comment "TODO: xyz."; p [] [txt "Hello!"]]
Explore in the REPL
$ utop
utop # #require "dream-html";;
utop # open Dream_html;;
utop # open HTML;;
utop # #install_printer pp;;
utop # p [class_ "hello"] [txt "world"];;
- : node = <p class="hello">world</p>
Test
Run the test and print out diff if it fails:
dune runtest # Will also exit 1 on failure
Set the new version of the output as correct:
dune promote
Prior art/design notes
Surface design obviously lifted straight from elm-html.
Similar to Webs as mentioned earlier (it turns out there are only a limited number of ways to do this kind of library).
Implementation inspired by both elm-html and Scalatags.