Emit HTML with a DSL
This feature integrates with kotlinx.htmlto directly emit HTML using Chunked transfer encoding without having to keepmemory for the whole HTML.
This feature is defined in the class io.ktor.html.HtmlContent
in the artifact io.ktor:ktor-html-builder:$ktor_version
.
dependencies { implementation "io.ktor:ktor-html-builder:$ktor_version"}
dependencies { implementation("io.ktor:ktor-html-builder:$ktor_version")}
<project> … <dependencies> <dependency> <groupId>io.ktor</groupId> <artifactId>ktor-html-builder</artifactId> <version>${ktor.version}</version> <scope>compile</scope> </dependency> </dependencies></project>
Installing
This feature doesn’t require installation.
Basic Usage
When generating the response, instead of calling the respond
/respondText
methods, you have to call ApplicationCall.respondHtml
:
call.respondHtml {
head {
title { +"Async World" }
}
body {
h1(id = "title") {
+"Title"
}
}
}
For documentation about generating HTML using kotlinx.html, please check its wiki.
Templates & Layouts
In addition to plain HTML generation with the DSL, ktor exposes a simple typed templating engine.You can use it to generate complex layouts in a typed way. It is pretty simple, yet powerful:
call.respondHtmlTemplate(MulticolumnTemplate()) {
column1 {
+"Hello, $name"
}
column2 {
+"col2"
}
}
class MulticolumnTemplate(val main: MainTemplate = MainTemplate()) : Template<HTML> {
val column1 = Placeholder<FlowContent>()
val column2 = Placeholder<FlowContent>()
override fun HTML.apply() {
insert(main) {
menu {
item { +"One" }
item { +"Two" }
}
content {
div("column") {
insert(column1)
}
div("column") {
insert(column2)
}
}
}
}
}
class MainTemplate : Template<HTML> {
val content = Placeholder<HtmlBlockTag>()
val menu = TemplatePlaceholder<MenuTemplate>()
override fun HTML.apply() {
head {
title { +"Template" }
}
body {
h1 {
insert(content)
}
insert(MenuTemplate(), menu)
}
}
}
class MenuTemplate : Template<FlowContent> {
val item = PlaceholderList<UL, FlowContent>()
override fun FlowContent.apply() {
if (!item.isEmpty()) {
ul {
each(item) {
li {
if (it.first) b {
insert(it)
} else {
insert(it)
}
}
}
}
}
}
}
You have to define classes implementing Template<TFlowContent>
,overriding the TFlowContent.apply
method and optionally definePlaceholder
or TemplatePlaceholder
properties just likein the example.
When generating the template with call.respondHtmlTemplate(MulticolumnTemplate()) { }
,you will get the template as receiver, and will be able to access the placeholdersdefined as properties in a typed way.