Components

Like React, a component is any function that returns HTML.

Warning

We still need to determine whether the functions names will be uppercase or not.

For now they will be uppercase.


fun MyComponent() -> HTML
╰╴No statement matched
{ <p>Hello templates!p> }
thp

Inside the HTML tags you can (mostly) write the HTML you already know.

Text interpolation

Interpolation inside HTML works the same way as string interpolation. Use brackets to insert an expression to the HTML:


fun MyComponent() -> HTML
╰╴No statement matched
{ val name = "John" <p>Hello {name}!p> }
thp
<p>Hello John!</p>

You can use any expression that can be converted to a String inside, like conditionals.


fun MyComponent() -> HTML
╰╴No statement matched
{ val name = "John" val is_vip = true <p> {if is_vip {"Welcome"} else {"Hi"}} {name}! p> }
thp
<p>Welcome John!</p>

Raw HTML

Text interpolated is always escaped:


fun MyComponent() -> HTML
╰╴No statement matched
{ val user_input = "BOLD" <p>answer: {user_input}p> }
thp
<p>answer: &lt;b&gt;BOLD&lt;/b&gt;</p>

To include raw html use the raw-html attribute (subject to change):


fun MyComponent() -> HTML
╰╴No statement matched
{ val user_input = "BOLD" <p>answer: <span raw-html={user_input}>span>p> }
thp
<p>
  answer: <span><b>BOLD</b></span>
</p>

Dynamic attributes

TODO: boolean attributes

Normal attributes (plain strings) work as you’d expect:


fun MyComponent() -> HTML
╰╴No statement matched
{ <button class="red">hellobutton> }
thp
<button class="red">hello</button>

Dynamic attributes are used when you want to use values from code. For those use brackets instead of double quotes:


fun MyComponent() -> HTML
╰╴No statement matched
{ val button_class = if true {"blue"} else {"yellow"} // Note the braces <button class={button_class}>hellobutton> }
thp
<button class="blue">hello</button>

Fragments

An HTML expression consist of a single tag that may have children inside. If you need to return multiple tags at once you can use fragments.

The following code doesn’t work as you would expect:


fun MyComponent() -> HTML
╰╴No statement matched
{ <p>hellop> // This is an error, an ignored expression <p>worldp> }
thp

Each <p> is a single expression, they are not grouped. And since we cannot have unused expressions, the code will not compile.

To have these two <p> tags as a single expression use a fragment: <></>


fun MyComponent() -> HTML
╰╴No statement matched
{ // This is the root "element" <> <p>hellop> // Now these two are together <p>worldp> }
thp
<p>hello</p>
<p>world</p>

Composition

To use a component inside another component call them as if it were an html tag:


fun User() -> HTML
╰╴No statement matched
{ <span>I am the userspan> } fun MyComponent() -> HTML { <> <p>statusp> <User /> // Here we are using the other component }
thp
<p>status</p>
<span>world</span>