kotlinadvanced
DSL for HTML Generation
Build a type-safe HTML DSL with Kotlin: lambda receivers, @DslMarker, and nested builders.
kotlinPress ⌘/Ctrl + Shift + C to copy
@DslMarker
annotation class HtmlDsl
@HtmlDsl
abstract class Element {
abstract fun render(indent: Int): String
protected fun indentation(level: Int) = " ".repeat(level)
}
class TextElement(private val text: String) : Element() {
override fun render(indent: Int) = "${indentation(indent)}$text\n"
}
@HtmlDsl
abstract class Tag(private val name: String) : Element() {
val children = mutableListOf<Element>()
val attributes = mutableMapOf<String, String>()
// Attribute helpers
var id: String
get() = attributes["id"] ?: ""
set(value) { attributes["id"] = value }
var className: String
get() = attributes["class"] ?: ""
set(value) { attributes["class"] = value }
fun attr(name: String, value: String) { attributes[name] = value }
// Text content
operator fun String.unaryPlus() {
children.add(TextElement(this))
}
override fun render(indent: Int): String = buildString {
val attrs = if (attributes.isNotEmpty())
attributes.entries.joinToString(" ", prefix = " ") { "${it.key}=\"${it.value}\"" }
else ""
if (children.isEmpty()) {
append("${indentation(indent)}<$name$attrs/>\n")
} else {
append("${indentation(indent)}<$name$attrs>\n")
children.forEach { append(it.render(indent + 1)) }
append("${indentation(indent)}</$name>\n")
}
}
}
// Concrete tags
class Html : Tag("html") {
fun head(init: Head.() -> Unit) = Head().also { it.init(); children.add(it) }
fun body(init: Body.() -> Unit) = Body().also { it.init(); children.add(it) }
}
class Head : Tag("head") {
fun title(text: String) { children.add(object : Tag("title") { init { +text } }) }
fun meta(init: Meta.() -> Unit) = Meta().also { it.init(); children.add(it) }
fun link(href: String, rel: String = "stylesheet") {
children.add(object : Tag("link") { init { attr("href", href); attr("rel", rel) } })
}
}
class Meta : Tag("meta")
class Body : Tag("body") {
fun h1(init: H1.() -> Unit) = H1().also { it.init(); children.add(it) }
fun p(init: P.() -> Unit) = P().also { it.init(); children.add(it) }
fun div(init: Div.() -> Unit) = Div().also { it.init(); children.add(it) }
fun ul(init: Ul.() -> Unit) = Ul().also { it.init(); children.add(it) }
fun a(href: String, init: A.() -> Unit) = A().also { it.attr("href", href); it.init(); children.add(it) }
}
class H1 : Tag("h1")
class P : Tag("p")
class A : Tag("a")
class Div : Tag("div") {
fun p(init: P.() -> Unit) = P().also { it.init(); children.add(it) }
fun span(init: Tag.() -> Unit) = object : Tag("span") {}.also { it.init(); children.add(it) }
}
class Ul : Tag("ul") {
fun li(init: Tag.() -> Unit) = object : Tag("li") {}.also { it.init(); children.add(it) }
}
// Entry point
fun html(init: Html.() -> Unit): Html = Html().apply(init)
fun main() {
val page = html {
head {
title("Kotlin DSL Demo")
meta { attr("charset", "utf-8") }
link("/styles.css")
}
body {
h1 {
className = "title"
+"Welcome to Kotlin DSL"
}
div {
id = "content"
className = "container"
p { +"This is a type-safe HTML builder." }
p { +"No string concatenation needed!" }
}
ul {
className = "features"
li { +"Type-safe" }
li { +"Readable" }
li { +"Extensible" }
}
a("https://kotlinlang.org") {
+"Learn Kotlin"
}
}
}
println(page.render(0))
}Use Cases
- Type-safe template generation
- Domain-specific configuration APIs
- Declarative UI construction patterns
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
kotlinadvanced
Type-Safe DSL Builder
Build domain-specific languages with Kotlin: receiver lambdas, @DslMarker, and nested builders.
Best for: Configuration DSLs for frameworks
#kotlin#dsl
kotlinintermediate
Type-Safe Builder for Configuration
Build configuration DSLs: server config, dependency injection setup, and nested builder patterns.
Best for: Application configuration DSLs
#kotlin#builder
kotlinadvanced
Builder Inference and Generic DSLs
Use @BuilderInference for type-safe DSL builders with generic type inference and collection construction.
Best for: Type-safe collection construction
#kotlin#builder
kotlinadvanced
Type-Safe DSL Builder Pattern
Create type-safe DSLs in Kotlin with receiver lambdas, @DslMarker, and nested builder scopes.
Best for: HTML/XML document generation
#kotlin#dsl