DOM Basics

Modifying the DOM

The DOM is built starting with an element, typically the BodyElement which is obtained easily as follows:

import io.kweb.*
import io.kweb.dom.element.*

fun main() {
  Kweb(port = 8091) {
     val body : BodyElement = doc.body
 }
}

Let’s create a button element as a child of the body element, we do this using the .new function (which is supported by all Element types):

import io.kweb.*
import io.kweb.dom.element.*

fun main() {
  Kweb(port = 8091) {
     doc.body.new {
         val button = button().text("Click Me!")
     }
   }
 }

As you can see, it’s easy to set the text of an element, you can also modify its attributes:

button.setAttribute("class", "bigbutton")

Or delete it:

button.delete()

Supported HTML tags

Kweb supports a significant subset of HTML tags like button(), p(), a(), table(), and so on. You can find a more complete list in the API documentation (scroll down to the Functions section). This provides a nice statically-typed HTML DSL, fully integrated with the Kotlin language.

If an tag doesn’t have explicit support in Kweb that’s not a problem. For example, here is how you might use the infamous and now-obsolete <blink> tag:

doc.body.new {
    val blink = element("blink").text("I am annoying!")
}

Extending Kweb to support new HTML tags

Adding support for new tags to Kweb is fairly simple. You can see how the existing functions are implemented. Feel free to submit a pull request via Github, or just submit an issue and we’ll do our best to add support.

Reading the DOM

You can read values from the DOM too:

doc.body.new {
    val label = h1().text("What is your name?")
    val clickMe = input(type = text)
    clickMe.setValue("Foo Bar")
    GlobalScope.launch {
        val v : String = clickMe.getValue().await()
        label.text("Value: $v")
    }
}

Notice that clickMe.getValue() doesn’t return a String, it returns a CompletableFuture<String>. This is because retrieving something from the DOM requires some communication with the browser and will take some time - and we don’t want to block while we wait.

This allows us to take advantage of Kotlin’s coroutines functionality to make this fairly seamless to the programmer (using GlobalScope.launch and await).

Yes, this example is a little pointless since we’re just setting the value and then immediately reading it, more realistic use cases will follow.

Next steps

Kweb really comes into its own when the above is combined with Kweb’s approach to State Management, particularly the render {} function.