Create a reusable HTML template
templating.Rdtemplate() is a function factory that captures a template expression and
returns a callable HTML renderer. The expression is evaluated
under the htmltools::withTags() environment, so tag functions such as
div() or p() are available.
Templates may define:
parameters: symbols or named defaults which are used as arguments to the renderer
content injection: if the template uses
..., the renderer passes...to the containing HTML nodes defined in the template.fragments: named subtemplates that can be optionally extracted from the template upon rendering by supplying
fragment = "name". Fragment names are required. If multiple fragment names are specified, fragments will be extracted and collated into a htmltools::tagList, in the order of names provided. If a specified fragment cannot be found, an error will be raised.
Usage
template(..., .envir = rlang::caller_env())
fragment(name = NULL, ...)Attributes
Attributes with non-leading underscores are
rewritten as hyphenated versions instead.
This means you can write
htmltools::div(data_foo="bar") which is converted to
htmltools::div(data-foo="bar").
Attributes with trailing underscores have their underscores stripped.
This means the you can write htmltools::tags$label(for_="foo") which
is converted to htmltools::tags$label(for="foo").
An escape hatch exists If you explicitly want
underscores in your attributes.
You may use double underscores, which
will be converted to single underscores
e.g.
htmltools::div(data__foo="bar") which is
converted to htmltools::div(data_foo="bar").
Built-in Helpers
Template bodies are evaluated in a freshwater environment that provides the following helpers:
form()— form helper with optional CSRF injection and method spoofing.csrf_token()— returns the current CSRF token string
Template Context
A template render context is maintained during evaluation which is used for fragment extraction and cache scoping. The template context is separate from the request context defined elsewhere.
Examples
# Example Fragment Usage
page_main <- template(
{
div(
h1("Dashboard"),
fragment(
p("Welcome back"),
name = "content"
),
small("2026")
)
}
)
page_main(fragment="content")
#> <p>Welcome back</p>
# Template slots
details <- template(name, age, {
nm <- sprintf("Hello, my name is: %s", name)
old <- sprintf("I am %s years old.", age)
div(
p(nm),
p(old)
)
})
details("Jim", 30)
#> <div>
#> <p>Hello, my name is: Jim</p>
#> <p>I am 30 years old.</p>
#> </div>
# Templates and fragments can also be combined
card <- template(
ttl, footer = NULL, {
div(
h2(ttl),
fragment(div("Card body"), name="body"),
if (!is.null(footer)) {
fragment(
div(footer),
name = "footer"
)
}
)
}
)
card("Card Title")
#> <div>
#> <h2>Card Title</h2>
#> <div>Card body</div>
#> </div>
card("Card Title", fragment="body")
#> <div>Card body</div>
card("Card Title", "Footer text", fragment = "footer")
#> <div>Footer text</div>
# Dots (content injection)
layout <- template({
htmltools::tagList(
head(meta(title = "foo")),
body(...)
)
})
layout(htmltools::div("content"))
#> <body>
#> <div>content</div>
#> </body>
# Attribute Norming
my_form <- template({
form(
label(for_ = "desc", "Description"),
input(
type = "text",
id = "desc",
data_user__id = "123"
)
)
})
my_form()
#> <form method="get">
#> <label for="desc">Description</label>
#> <input type="text" id="desc" data-user_id="123"/>
#> </form>