Technology Preview: Jetpack Compose for Web

First came the desktop, now comes the world wide web: Jetpack Compose advances to the browser! Today, we are releasing the first technology preview of Jetpack Compose for Web. While we keep actively developing Compose for Desktop toward its 1.0 release, this is the next chapter in our multiplatform story for Jetpack Compose, bringing Google’s toolkit for building reactive user interfaces with Kotlin to the web.

Visit the Compose for Web Landing Page

First, a small disclaimer: as a technology preview, Compose for Web is far from being done – we don’t yet provide learning materials, tutorials, or documentation, and we have not done any performance optimizations yet (so hold your benchmarks!). It is certainly not yet ready for use in any production application.

We still want to provide a first look at this new Kotlin/JS-powered target for Jetpack Compose, and give adventurous folks in the Kotlin community a chance to get their hands on this new technology. We hope that your feedback, ideas, and use cases can help us guide our development of Compose for Web going forward!

So, if you are ready for an adventure and excited about what the future of Compose holds, read on and learn about this very first version of Compose for Web.

Powered by Kotlin Multiplatform

Jetpack Compose for Web works on top of Kotlin Multiplatform, meaning you can develop an Android, Desktop, and Web application using Jetpack Compose as your UI framework – all from within the same project. Kotlin Multiplatform allows you to share platform-agnostic code and functionality like your business logic through common code, while still being able to implement and use platform-specific functionality from Android, Desktop JVM, and the JavaScript ecosystem alike.

In this preview, you can already freely reuse all core Compose state management concepts across the platforms. Compose for Web currently does not allow you to directly reuse existing widgets (unlike the Android and Desktop targets for Jetpack Compose, which allow direct code sharing for most widgets out of the box).

However, you can use Kotlin Multiplatform’s expect/actual mechanism to build your own common widgets with implementations for all three platforms. This way, you can apply the same principles to build your app UI on mobile, desktop, and web.

DOM API and Multiplatform Widgets

This technology preview includes two types of APIs that we are currently exploring and designing for declaring user interfaces in Kotlin code with Compose: a DOM API, and a web implementation of the widgets you already know from Jetpack Compose for Desktop and Android.

Composable DOM API

The composable DOM API gives you full control over the Document Object Model, the structure defining your website. You specify the state, behavior, and logic of your reactive user interface using the concepts from Jetpack Compose, but express your design and layout in the language of the browser, constructing and styling HTML elements.

Just like you would use tags in HTML or JSX like

<a>

,

<div>

or

<p>

to describe your layouts, you use Compose for Web’s type-safe domain-specific language to express these concepts in Kotlin code:

fun main() {
    renderComposable("root") {
        var platform by remember { mutableStateOf("a platform") }
        P {
            Text("Welcome to Compose for $platform! ")
            Button(attrs = { onClick { platform = "Web" } }) {
                Text("...for what?")
            }
        }
        A("https://www.jetbrains.com/lp/compose-web") {
            Text("Learn more!")
        }
    }
}

We are also designing a typesafe DSL for style sheets, with which you can express CSS rules in your Kotlin code, and even modify styles based on the state of your Compose application:

class MyStyle: StyleSheet(AppStylesheet) {
    val styledHeading by style {
        color("#27282c")
        fontSize(60.px)

        media(maxWidth(640.px)) {
            self style {
                backgroundColor("lightgray")
                this.justifyContent(JustifyContent.Center)
                fontSize(42.px)
            }
        }
    }
}

Multiplatform Widgets

With multiplatform widgets, we are experimenting with creating a set of layout primitives, widgets, and APIs that mimic the features you already know from Jetpack Compose for Desktop and Android. These web implementations are currently self-contained in their own packages, and implement only a small subset of the interfaces found on the other targets.

They try to approximate the behavior of the canvas-based implementations used in the other Jetpack Compose targets. Under the hood, they recreate the look and feel of the components on top of the DOM, under the constraints of the browser layout engine.

To try these widgets and get a feeling for their current state, you can copy-paste an implementation of a Jetpack Compose user interface into a Compose for Web project, and adjust the import statements to use the multiplatform widgets:

@Composable
fun SizeAndColorDemo() {
    val defaultFontSize = 0.79f
    val fontSize = remember { mutableStateOf(defaultFontSize) }
    val subtitleColor = remember { mutableStateOf(Color(0, 0, 200)) }
    Column {
        Text(
            "Change size",
            color = subtitleColor.value,
            size = fontSize.value.em,
            modifier = Modifier.clickable {
                subtitleColor.value = Color.Yellow
            }
        )
        Slider(
            fontSize.value,
            onValueChange = { value ->
                fontSize.value = value
            },
            valueRange = 0.1f..1.2f,
            steps = 80,
            modifier = Modifier.width(200.dp)
        )
        Button(
            onClick = {
                fontSize.value = defaultFontSize
            }
        ) {
            Text("reset view")
        }
    }
}

We are experimenting with these types of unified widgets to try and gain a better understanding of their feasibility. These experiments will also help us improve the multiplatform development experience down the line.

Example Applications

To give you a starting point for your own exploration of this technology preview for Jetpack Compose for Web, we provide a few example applications that demonstrate using the DOM and Widget APIs, respectively.

Experience and Influence Jetpack Compose for Web!

So, are you ready to go on a Compose for Web adventure? Go ahead and play with one of the sample projects linked above, or check out the installation instructions. We’d love it if you would share your use cases, ideas, feedback, and opinions with our team! Join

#compose-web

on the Kotlin Slack to chat and discuss, and report any problems you run into in the project’s issue tracker.

Get started with Jetpack Compose for Web

We look forward to hearing from you, and hope you enjoy this first glance at this new target for Jetpack Compose!

Special thanks go out to Andrei Shikov for his help and tireless efforts in making the Jetpack Compose compiler plugin and its runtime work with Kotlin/JS, as well as to our friends at Google for working with us on advancing their amazing Jetpack Compose technology.