DEV Community

Cover image for Building Your Own DSL with @resultBuilder in Swift: HTML Builder
Karan Pal
Karan Pal

Posted on • Originally published at Medium

Building Your Own DSL with @resultBuilder in Swift: HTML Builder

Building Your Own DSL with @resultBuilder in Swift: HTML Builder

๐Ÿš€ Ready to transform messy HTML string concatenation into beautiful, type-safe Swift code?

In Part 1 of this series, we demystified the magic behind SwiftUI's declarative syntax. Now it's time to build something real - a complete HTML DSL that you can actually use in production!

๐ŸŽฏ What We're Building

By the end of this tutorial, you'll transform this nightmare:

var html = "<html>" html += "<head><title>" + title + "</title></head>" html += "<body>" html += "<div class=\"container\">" html += "<h1>" + heading + "</h1>" if showContent { html += "<p>" + content + "</p>" } html += "</div></body></html>" 
Enter fullscreen mode Exit fullscreen mode

Into this beauty:

let webpage = html { head { title("My Awesome Site") } body { div(class: "container") { h1("Welcome!") if showContent { p("Amazing content here") } } } } 
Enter fullscreen mode Exit fullscreen mode

โœจ What You'll Master

๐Ÿ› ๏ธ Complete HTML DSL implementation - Every element you need, properly structured

๐Ÿ”’ Automatic XSS protection - Built-in HTML escaping for security

๐ŸŽฏ Type-safe markup - Catch structural errors at compile time

๐Ÿงช Production testing strategies - Comprehensive test suites for DSLs

โšก Modern Swift integration - Variables, loops, and conditionals that just work

๐Ÿ—๏ธ Why DSLs Matter Beyond SwiftUI

Every Swift developer knows SwiftUI uses @resultBuilder, but the real power comes when you solve your own domain problems:

Server-side Swift developers โ†’ Generate HTML responses without templating engines

Email automation โ†’ Create dynamic email templates with type safety

Static site generation โ†’ Build documentation sites with Swift

Configuration management โ†’ Declare complex app settings declaratively

๐Ÿ’ป Core Architecture Revealed

The magic starts with a solid foundation:

protocol HTMLElement { func render() -> String } struct Element: HTMLElement { let tag: String let attributes: [String: String] let children: [HTMLElement] let isSelfClosing: Bool func render() -> String { // Automatic HTML generation with proper escaping } } 
Enter fullscreen mode Exit fullscreen mode

Then we add the @resultBuilder that makes the beautiful syntax possible:

@resultBuilder struct HTMLBuilder { static func buildBlock(_ components: HTMLElement...) -> HTMLElement { ElementGroup(Array(components)) } static func buildOptional(_ component: HTMLElement?) -> HTMLElement { component ?? ElementGroup([]) } // Automatic string-to-HTML conversion static func buildExpression(_ expression: String) -> HTMLElement { TextNode(expression) // With XSS protection built-in! } } 
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”ง Production-Ready Patterns

Complete element support for all your HTML needs:

func div(class: String? = nil, @HTMLBuilder content: () -> HTMLElement) -> HTMLElement func p(@HTMLBuilder content: () -> HTMLElement) -> HTMLElement func img(src: String, alt: String) -> HTMLElement // Plus 20+ more elements... 
Enter fullscreen mode Exit fullscreen mode

Smart conditional rendering that feels natural:

let userProfile = div { h1(user.name) if user.isVerified { span(class: "verified") { "โœ“ Verified" } } for skill in user.skills { span(class: "skill") { skill } } } 
Enter fullscreen mode Exit fullscreen mode

Automatic security through HTML escaping:

p { "<script>alert('xss')</script>" } // Safely renders: <p>&lt;script&gt;alert('xss')&lt;/script&gt;</p> 
Enter fullscreen mode Exit fullscreen mode

๐Ÿงช Testing Like a Pro

DSLs need robust testing. Here's how we ensure reliability:

func testConditionalContent() { let element = div { p("Always visible") if true { span("Sometimes visible") } } let html = element.render() XCTAssertTrue(html.contains("Always visible")) XCTAssertTrue(html.contains("Sometimes visible")) } 
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Real-World Benefits

For teams:

  • Reduced bugs - No more missing closing tags
  • Better readability - Code that looks like what it produces
  • Easier maintenance - Refactor HTML structure with Swift tools

For projects:

  • Type safety - Catch errors at compile time
  • Security - XSS protection built-in
  • Performance - Efficient string generation
  • Flexibility - Easy to extend and customize

๐Ÿš€ What's Next?

This complete tutorial covers:

  • Foundation architecture and design decisions
  • Complete @resultBuilder implementation
  • Full HTML element library
  • Production testing strategies
  • Integration with modern Swift features
  • Real-world usage examples

Part 3 of this series will cover advanced patterns, performance optimization, and production deployment strategies.

๐Ÿ“– Read the Complete Guide

Ready to master DSL creation? The full tutorial includes complete working code, detailed explanations, and production-ready patterns:

Building Your Own DSL with @resultBuilder in Swift: HTML Builder

๐Ÿ’ฌ Join the Discussion

What would you build with a custom DSL? Share your ideas in the comments!

  • Configuration management for complex apps?
  • API response builders for server-side Swift?
  • Test data generation for your test suites?
  • Custom markup languages for your domain?

๐Ÿ”— Stay Connected

Follow me for more Swift deep dives and iOS development insights:

Enjoyed this? Buy me a coffee โ˜• to fuel more comprehensive Swift tutorials!

Top comments (0)