kotlinadvanced
Type-Safe DSL Builder Pattern
Create type-safe DSLs in Kotlin with receiver lambdas, @DslMarker, and nested builder scopes.
kotlinPress ⌘/Ctrl + Shift + C to copy
@DslMarker
annotation class HtmlDsl
@HtmlDsl
class HTML {
private val children = mutableListOf<Element>()
fun head(block: Head.() -> Unit) { children.add(Head().apply(block)) }
fun body(block: Body.() -> Unit) { children.add(Body().apply(block)) }
override fun toString() =
"<html>\n${children.joinToString("\n") { " $it" }}\n</html>"
}
@HtmlDsl
open class Element(private val tag: String) {
protected val children = mutableListOf<Any>()
protected val attributes = mutableMapOf<String, String>()
fun attr(key: String, value: String) { attributes[key] = value }
override fun toString(): String {
val attrs = if (attributes.isEmpty()) ""
else " " + attributes.entries.joinToString(" ") { "${it.key}=\"${it.value}\"" }
val content = children.joinToString("\n") { " $it" }
return if (children.isEmpty()) "<$tag$attrs />"
else "<$tag$attrs>\n$content\n</$tag>"
}
}
class Head : Element("head") {
fun title(text: String) { children.add("<title>$text</title>") }
fun meta(name: String, content: String) {
children.add("<meta name=\"$name\" content=\"$content\" />")
}
}
@HtmlDsl
class Body : Element("body") {
fun h1(text: String) { children.add(Element("h1").apply { children.add(text) }) }
fun p(text: String) { children.add(Element("p").apply { children.add(text) }) }
fun div(block: Body.() -> Unit) {
val el = Body(); el.block()
children.add(Element("div").apply { this.children.addAll(el.children) })
}
fun ul(block: ListBuilder.() -> Unit) { children.add(ListBuilder().apply(block)) }
fun a(href: String, text: String) {
children.add(Element("a").apply { attr("href", href); children.add(text) })
}
}
class ListBuilder : Element("ul") {
fun li(text: String) { children.add(Element("li").apply { children.add(text) }) }
}
fun html(block: HTML.() -> Unit): HTML = HTML().apply(block)
fun main() {
val page = html {
head {
title("My Page")
meta("description", "A type-safe HTML DSL")
}
body {
h1("Welcome!")
p("This is built with a Kotlin DSL.")
div {
p("Inside a div")
ul {
li("First item")
li("Second item")
li("Third item")
}
}
a("https://kotlinlang.org", "Learn Kotlin")
}
}
println(page)
}Use Cases
- HTML/XML document generation
- Configuration DSLs for frameworks
- Type-safe query builders
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
kotlinadvanced
DSL for HTML Generation
Build a type-safe HTML DSL with Kotlin: lambda receivers, @DslMarker, and nested builders.
Best for: Type-safe template generation
#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