This library contains functions for building HTML elements and styling them with CSS.
See full project set up in akryl-core repository.
- Add jcenter repository:
repositories {
jcenter()
...
}
- Add dependencies:
kotlin {
sourceSets {
main {
dependencies {
implementation "io.akryl:akryl-dom:0.+"
implementation npm("react-dom", "16.12.0")
}
}
}
}
Instead of JSX, the library uses functions with named arguments.
To create a Virtual DOM element, call a function like Div
, Span
or Img
and pass HTML attributes as arguments.
// Kotlin
img(className = "my-image", src = "example.png")
// JSX
<img className="my-image" src="example.png"/>
Use children
, child
, and text
to pass children to an element.
If an element contains no attributes, pass children as varargs.
// Kotlin
import io.akryl.dom.html.*
div(id = "root", children = listOf(
header(text = "text"),
div(className = "inner", child = img(src = "example.png")),
footer(
p(text = "first paragraph"),
p(text = "second paragraph")
)
))
// JSX
<div id="root">
<header>text</header>
<div className="inner"><img src="example.png"/></div>
<footer>
<p>first paragraph</p>
<p>second paragraph</p>
</footer>
</div>
Use ReactDom.render
to apply elements or components to document.
import io.akryl.component
import io.akryl.dom.html.*
import react_dom.ReactDom
import kotlin.browser.document
fun app() = component {
div(text = "Hello, World!")
}
ReactDom.render(app(), document.getElementById("app"))
The library provides three ways to style elements:
- CSS classes
- Inline CSS
- Inline styles
All CSS happens inside Kotlin, so you don't need to write separate CSS files. It provides statically typed styling that leads to fewer errors and better refactoring.
All CSS properties declarations follow this syntax:
propertyName(singleValue)
propertyName.enumValue()
propertyName.groupValue(additional, arguments)
For example:
// single value properties
width(100.px)
paddingLeft(1.em)
content(" ")
// enum properties
display.flex()
overflow.hidden()
flexDirection.column()
border.solid(1.px, Color.red)
// mixed properties
color.red()
color(0xFF0000)
// complex properties
transform
.translate(100.px, 200.px)
.scale(1.5)
Use css
function to create scoped classes.
These classes will not conflict with each other even if they have identical names on Kotlin side.
It works similar to libraries like css-modules.
// Kotlin
import io.akryl.dom.css.css
import io.akryl.dom.css.invoke
import io.akryl.dom.css.properties.*
val foo by css(
color.red()
)
val bar by css(
display.flex(),
hover(
backgroundColor.gray()
),
foo(
flex(1, 1, 100.pct)
)
)
/* CSS */
.foo {
color: red;
}
.bar {
display: flex;
}
.bar:hover {
background: gray;
}
.bar .foo {
flex: 1 1 100%;
}
All HTML elements have argument named css
that allows to inject inline CSS code.
It is something like styled-components and elm-css.
// Kotlin
import io.akryl.dom.css.properties.*
import io.akryl.dom.html.*
div(
css = listOf(
backgroundColor.black(),
color.white()
),
text = "Inline CSS example"
)
CSS will be connected to an element via the className
attribute.
The stylesheet itself will be injected into the document head.
The library caches CSS blocks, so, all identical instances will point to a single class name.
The code above will be converted into this:
/* CSS */
.css-12345678 {
background: black;
color: white;
}
<!-- HTML -->
<div class="css-12345678">
Inline CSS example
</div>
With inline CSS, you can use inner selectors like tags, pseudo-selectors or other classes.
It is a value for the style
attribute of an element.
Here you cannot use inner selectors, but only define CSS properties of a particular element.
This is useful when styles are changing often or have too many possible values.
Example:
// Kotlin
import io.akryl.dom.css.properties.*
import io.akryl.dom.html.*
div(
style = listOf(
transform.translate(100.px, 200.px),
willChange("transform")
),
text = "div with inline styles"
)
Will be converted to:
<!-- HTML -->
<div style="transform: translate(100px, 200px); will-change: transform;">
div with inline styles
</div>