You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
6.2 KiB
247 lines
6.2 KiB
2 years ago
|
# Building the UI with with the Compose HTML library
|
||
4 years ago
|
|
||
2 years ago
|
In this tutorial we will look at several examples that use the Composable HTML/CSS DSL to describe the user interface for your web application.
|
||
4 years ago
|
|
||
|
### Entry point
|
||
|
|
||
2 years ago
|
The Compose HTML library needs an HTML node that will be a root of its composition. Inside this root node, Compose then manages its own DOM tree.
|
||
4 years ago
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
renderComposable(rootElementId = "root") {
|
||
|
// content goes here
|
||
|
}
|
||
|
```
|
||
|
|
||
2 years ago
|
### HTML tags
|
||
4 years ago
|
|
||
|
Let's have a look at the Composable for a `Div` tag (most other tags have the same signature):
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
Div(
|
||
|
attrs = {
|
||
|
// specify attributes here
|
||
3 years ago
|
style {
|
||
|
// specify inline style here
|
||
|
}
|
||
4 years ago
|
}
|
||
|
) {
|
||
|
// div content goes here
|
||
|
}
|
||
|
```
|
||
|
|
||
|
For convenience, some tags like `Input`, `A`, `Form`, or `Img` allow you to specify some extra parameters in the signature that are specific to the respective HTML tag. For example, let’s look at the `Input` tag:
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
Input(
|
||
|
type = InputType.Text, // All InputTypes supported
|
||
3 years ago
|
attrs = {}
|
||
4 years ago
|
)
|
||
|
```
|
||
|
|
||
|
We can use the `type` parameter which is provided for our convenience, or can use the `attrs` block to specify the input type:
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
Input(attrs = { type(InputType.Text) })
|
||
|
```
|
||
|
|
||
|
### Text
|
||
|
|
||
2 years ago
|
The `Text` allows you to add text content to an HTML tag. Besides the text content it represents, it does not have any parameters:
|
||
4 years ago
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
Text("Arbitrary text")
|
||
|
```
|
||
|
|
||
|
If you want to apply styles to text, it needs to be wrapped in a container with a style applied, like a `Span` or `P`:
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
Span(
|
||
3 years ago
|
attrs = { style { color(Color.red) } } // inline style
|
||
4 years ago
|
) {
|
||
|
Text("Red text")
|
||
|
}
|
||
|
```
|
||
|
|
||
|
This corresponds to the following HTML code:
|
||
|
```html
|
||
|
<span style="color: red;">Red text</span>
|
||
|
```
|
||
|
|
||
|
### Attributes
|
||
|
|
||
|
The `attrs` parameter (which we’ve already seen in some of the previous examples) allows us to specify element's attributes and properties.
|
||
|
|
||
|
The most flexible way to define attributes is by using the `attr` function, which allows you to specify the attribute name and its value.
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
Div(
|
||
|
attrs = {
|
||
|
attr(attr = "custom_attr", value = "its_value")
|
||
|
}
|
||
|
) { /* content */ }
|
||
|
```
|
||
|
|
||
2 years ago
|
However, with this approach, Compose is not able to validate that the attribute exists on the HTML element, or is valid. This is why we also provide a set of helper functions for common attributes.
|
||
4 years ago
|
|
||
|
#### Common attributes
|
||
|
|
||
|
Here are some examples of common attributes that are available for most Composables representing HTML tags:
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
attrs = {
|
||
|
id("elementId")
|
||
|
classes("cl1", "cl2")
|
||
|
hidden(false)
|
||
|
title("title")
|
||
|
draggable(Draggable.Auto)
|
||
|
dir(DirType.Auto)
|
||
|
lang("en")
|
||
|
contentEditable(true)
|
||
|
}
|
||
|
```
|
||
|
|
||
|
#### Element specific attributes
|
||
|
|
||
|
Depending on the element you are working with, you may also have access to some specific attributes – attributes that are only meaningful for this particular tag. For example, the `A` tag provides some specific attributes, that are specific to hyperlinks:
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
A(
|
||
|
attrs = {
|
||
|
href("https://localhost:8080/page2")
|
||
|
target(ATarget.Blank)
|
||
|
rel(ARel.Next)
|
||
|
hreflang("en")
|
||
|
download("https://...")
|
||
|
}
|
||
|
) {}
|
||
|
```
|
||
|
|
||
|
Some other elements that provide specific attributes include:
|
||
|
- Button
|
||
|
- Form
|
||
|
- Input
|
||
|
- Option
|
||
|
- Select
|
||
|
- OptGroup
|
||
|
- TextArea
|
||
|
- Img
|
||
|
|
||
|
To discover all attributes that are available in your current scope, you can use your IDE’s autocomplete feature. As we evolve these APIs, we also plan to add detailed documentation for them.
|
||
|
|
||
|
#### Events
|
||
|
|
||
|
You can declare event listeners in the `attrs` block:
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
Button(
|
||
|
attrs = {
|
||
|
onClick { println("Button clicked") }
|
||
|
}
|
||
|
) { Text("Button") }
|
||
|
```
|
||
|
|
||
|
There are more examples about events handling here - [Events Handling](../Events_Handling/README.md)
|
||
|
|
||
|
### Style
|
||
|
|
||
|
There are ways to set the style for a component:
|
||
|
- Using inline styles
|
||
|
- Using stylesheets
|
||
|
|
||
|
You can declare inline styles via the `style` block of a component:
|
||
|
|
||
4 years ago
|
``` kotlin
|
||
4 years ago
|
Div(
|
||
3 years ago
|
attrs = {
|
||
|
style {
|
||
|
display(DisplayStyle.Flex)
|
||
|
padding(20.px)
|
||
|
|
||
|
// custom property
|
||
|
property("font-family", "Arial, Helvetica, sans-serif")
|
||
|
}
|
||
4 years ago
|
}
|
||
|
) { /* content goes here */ }
|
||
|
```
|
||
|
|
||
4 years ago
|
You can find a more detailed overview of the style DSL, as well as additional examples here - [Style DSL](../Style_Dsl/README.md)
|
||
|
|
||
|
### Runnable example
|
||
|
|
||
|
```kotlin
|
||
3 years ago
|
import androidx.compose.runtime.Composable
|
||
|
import org.jetbrains.compose.web.attributes.*
|
||
|
import org.jetbrains.compose.web.css.*
|
||
|
import org.jetbrains.compose.web.dom.*
|
||
|
import org.jetbrains.compose.web.renderComposable
|
||
4 years ago
|
|
||
|
fun main() {
|
||
|
renderComposable(rootElementId = "root") {
|
||
|
Div(
|
||
|
attrs = {
|
||
|
// specify attributes here
|
||
3 years ago
|
style {
|
||
|
// specify inline style here
|
||
|
}
|
||
4 years ago
|
}
|
||
|
) {
|
||
|
Text("A text in <div>")
|
||
|
}
|
||
|
|
||
|
Input(
|
||
|
type = InputType.Text, // All InputTypes supported
|
||
3 years ago
|
attrs = {}
|
||
4 years ago
|
)
|
||
|
|
||
|
Text("Arbitrary text")
|
||
|
|
||
3 years ago
|
Span({
|
||
3 years ago
|
style { color(Color.red) } // inline style
|
||
3 years ago
|
}) {
|
||
4 years ago
|
Text("Red text")
|
||
|
}
|
||
|
|
||
|
Div(
|
||
|
attrs = {
|
||
|
id("elementId")
|
||
|
classes("cl1", "cl2")
|
||
3 years ago
|
hidden()
|
||
4 years ago
|
title("title")
|
||
|
draggable(Draggable.Auto)
|
||
|
dir(DirType.Auto)
|
||
|
lang("en")
|
||
|
contentEditable(true)
|
||
|
|
||
|
// custom attr
|
||
|
attr(attr = "custom_attr", value = "its_value")
|
||
|
}
|
||
|
) { /* content */ }
|
||
|
|
||
|
A(
|
||
|
attrs = {
|
||
|
href("https://localhost:8080/page2")
|
||
|
target(ATarget.Blank)
|
||
|
hreflang("en")
|
||
|
download("https://...")
|
||
|
}
|
||
|
) { Text("Link") }
|
||
|
|
||
|
Button(
|
||
|
attrs = {
|
||
|
onClick { println("Button clicked") }
|
||
|
}
|
||
|
) { Text("Button") }
|
||
|
|
||
3 years ago
|
Div({
|
||
|
style {
|
||
4 years ago
|
display(DisplayStyle.Flex)
|
||
|
padding(20.px)
|
||
|
|
||
|
// custom property
|
||
3 years ago
|
property("font-family", "Arial, Helvetica, sans-serif")
|
||
4 years ago
|
}
|
||
3 years ago
|
}) { Text("Text in Div with inline style") }
|
||
4 years ago
|
}
|
||
|
}
|
||
3 years ago
|
```
|