hypertext
html element construction for R.
hypertext provides a deterministic, framework-agnostic DSL for building html nodes and rendering them to a string.
- dependency-free. zero package imports. lightweight is the right weight, as suggested in the tinyverse philosophy.
- does not implement templating, dependency management, or widgets/framework integrations.
- heavily inspired by {htmltools}.
installation
install the stable version from CRAN:
install.packages("hypertext")or get the development version from github:
devtools::install_github("sigflux/hypertext")quick start
page <- tag_list(
doctype(),
tags$html(
tags$head(
tags$title("hypertext")
),
tags$body(
tags$h1("Hello"),
tags$p(
class = c("lead", "mb-2"),
"Server-side HTML."
),
tags$input(
type = "text",
placeholder = "enter your nickname"
),
tags$button(
"Click"
)
)
)
)
page
#> <!DOCTYPE html>
#> <html>
#> <head>
#> <title>hypertext</title>
#> </head>
#> <body>
#> <h1>Hello</h1>
#> <p class="lead mb-2">Server-side HTML.</p>
#> <input type="text" placeholder="enter your nickname" />
#> <button>Click</button>
#> </body>
#> </html>rendering
render() takes a tag tree and returns a single HTML string:
x <- tags$p(
class = "lead",
"hello"
)
# `x` contains the tag tree
class(x)
#> [1] "hypertext.tag"
x
#> <p class="lead">hello</p>
# rendering produces an HTML string:
render(x)
#> [1] "<p class=\"lead\">hello</p>"you can render() directly to an html file by supplying the file parameter:
page <- tag_list(
doctype(),
tags$html(
tags$head(
tags$title("hypertext")
),
tags$body(
tags$h1("Hello"),
tags$p(
class = c("lead", "mb-2"),
"Server-side HTML."
),
tags$input(
type = "text",
placeholder = "enter your nickname"
),
tags$button(
"Click"
)
)
)
)
render(x = page, file = "index.html")tag lists
tag_list() groups sibling nodes without wrapping them in a parent element.
header <- tag_list(
tags$h1("hello"),
tags$p(
class = "lead",
"welcome aboard."
)
)
# `header` is a "hypertext.tag.list" object:
class(header)
#> [1] "hypertext.tag.list" "list"
header
#> <h1>hello</h1>
#> <p class="lead">welcome aboard.</p>raw html
raw_html() marks a string as pre-rendered HTML so that render() outputs it verbatim, without escaping. useful for injecting inline scripts, styles, SVG markup, or any content that is already valid HTML.
tags$div(
raw_html("<svg viewBox='0 0 100 100'><circle cx='50' cy='50' r='40'/></svg>")
)
#> <div><svg viewBox='0 0 100 100'><circle cx='50' cy='50' r='40'/></svg></div>doctype() is a convenience wrapper around raw_html("<!DOCTYPE html>").
usage in frameworks
ambiorix
ambiorix is the perfect example of a web framework where you will find {hypertext} useful:
library(ambiorix)
library(hypertext)
app <- Ambiorix$new(port = 3000L)
app$get("/", function(req, res) {
html <- tags$h1("hello, world!") |>
render()
res$send(html)
})
app$get("/about", function(req, res) {
html <- tag_list(
tags$h1("about us"),
tags$p(
"minimal ",
tags$strong("html construction"),
" for R."
)
) |>
render()
res$send(html)
})
app$get("/team", function(req, res) {
teammates <- c("you", "me", "other")
html <- tags$div(
class = "team",
tags$p("meet the team:"),
tags$ul(
lapply(teammates, tags$li)
)
) |>
render()
res$send(html)
})
app$start()shiny
shiny already has {htmltools} tags internally, so you do not need {hypertext} in your shiny apps, but in case you do:
library(shiny)
library(bslib)
library(hypertext)
# use `hypertext::tags` explicitly to avoid clashing with `shiny::tags`.
ht <- hypertext::tags
card <- function(title, body) {
ht$div(
class = "card mt-3",
ht$div(
class = "card-header",
title
),
ht$div(
class = "card-body",
ht$p(
class = "card-text",
body
)
)
)
}
content <- ht$div(
class = "container py-4",
card("First card", "Some quick example text."),
card("Second card", "Another body of text.")
) |>
render()
ui <- page(
theme = bs_theme(version = 5L),
# hypertext renders an HTML string, so wrap in shiny::HTML()
HTML(content)
)
server <- function(input, output, session) {}
shinyApp(ui, server)