The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

hypertext

R-CMD-check CRAN status Lifecycle: stable

html element construction for R.

hypertext provides a deterministic, framework-agnostic DSL for building html nodes and rendering them to a string.

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>").

custom tags

tag() creates elements for any tag name, including web components and custom elements not in the built-in tags list. it takes 3 arguments:

content <- tag(
  tag_name = "calcite-action-bar",
  layout = "horizontal"
)

content
#> <calcite-action-bar layout="horizontal"></calcite-action-bar>

nest them freely with each other and with built-in tags:

page <- tags$div(
  class = "app",
  tag(
    tag_name = "calcite-shell",
    tag(
      tag_name = "calcite-shell-panel",
      slot = "panel-start",
      tag(
        tag_name = "calcite-action-bar",
        tag(
          tag_name = "calcite-action",
          text = "Layers",
          icon = "layers"
        ),
        tag(
          tag_name = "calcite-action",
          text = "Basemaps",
          icon = "basemap"
        )
      )
    ),
    tags$div(id = "map")
  )
)

page
#> <div class="app">
#>   <calcite-shell>
#>     <calcite-shell-panel slot="panel-start">
#>       <calcite-action-bar>
#>         <calcite-action text="Layers" icon="layers"></calcite-action>
#>         <calcite-action text="Basemaps" icon="basemap"></calcite-action>
#>       </calcite-action-bar>
#>     </calcite-shell-panel>
#>     <div id="map"></div>
#>   </calcite-shell>
#> </div>

for self-closing elements, set tag_type = "void":

content <- tag(
  tag_name = "my-icon",
  name = "home",
  tag_type = "void"
)

content
#> <my-icon name="home" />

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)

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.