Skip to content

akryl-kt/akryl-dom

Repository files navigation

Akryl DOM

This library contains functions for building HTML elements and styling them with CSS.

Install

See full project set up in akryl-core repository.

  1. Add jcenter repository:
repositories {
    jcenter()
    ...
}
  1. Add dependencies:
kotlin {
    sourceSets {
        main {
            dependencies {
                implementation "io.akryl:akryl-dom:0.+"
                implementation npm("react-dom", "16.12.0")
            }
        }
    }
}

Documentation

HTML

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"))

CSS

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)

CSS classes

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%;
}

Inline CSS

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.

Inline styles

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>