Learn Jetpack Compose - Desktop, Web, & Multiplatform
Episode 17 of 23

Learn Jetpack Compose - Desktop, Web, & Multiplatform

This episode explores beyond Android: Compose Multiplatform basics, desktop and web targets, sharing UI components between platforms, and its limitations and practical use cases.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Introduction

The concepts you've learned — composables, state, recomposition, modifiers — aren't limited to Android. Compose Multiplatform brings the same paradigm to desktop (JVM), web (Wasm and JS), and iOS, sharing UI code between platforms.

This is not a WebView and not a self-rendered framework like Flutter: Compose Multiplatform uses a shared canvas alongside the native UI toolkit on each target. One composable can be used on Android and desktop without changes.

Episode 17 covers Compose Multiplatform basics, desktop and web targets, sharing components, and its limitations and practical use cases.

Compose Multiplatform Basics

Module Structure

A Compose Multiplatform project uses Gradle Kotlin Multiplatform. Shared code lives in commonMain, and platform-specific code in each source set:

KotlinTarget Compose Multiplatform
kotlin {
    androidTarget()
    jvm("desktop")
    wasmJs()
 
    sourceSets {
        commonMain.dependencies {
            implementation(compose.runtime)
            implementation(compose.foundation)
            implementation(compose.material3)
            implementation(compose.ui)
        }
        val desktopMain by getting {
            dependencies {
                implementation(compose.desktop.currentOs)
            }
        }
    }
}

commonMain holds the shared Compose dependencies, and desktopMain adds compose.desktop for the JVM target. Android, desktop, and web use the same UI from commonMain.

Platform-specific Source Sets

Platform-dependent code is declared with expect and actual:

Kotlinexpect dan actual
expect fun getPlatformName(): String
 
// di desktopMain
actual fun getPlatformName(): String = "Desktop"
 
// di androidMain
actual fun getPlatformName(): String = "Android"

expect declares a shared API, and actual provides the implementation per platform. This pattern is used for things like clipboard, storage, and notifications.

Deploying to Desktop and Web

Running on Desktop

The desktop target runs as a standalone JVM application:

Menjalankan aplikasi desktop
./gradlew :composeApp:run

./gradlew :composeApp:run launches the desktop application in development mode. For distribution, packageDistributionForCurrentOS generates an installer per OS.

Web with Wasm

For web, Compose compiles to WebAssembly:

Menjalankan target web
./gradlew :composeApp:wasmJsBrowserRun

./gradlew :composeApp:wasmJsBrowserRun runs the application in the browser. Its output is static, so it can be deployed to any hosting — a pattern that suits dashboards and internal tools.

Sharing UI Components

One Composable, Many Platforms

UI foundations that aren't platform-specific can be shared directly:

KotlinUI bersama
@Composable
fun KartuPesan(pesan: String) {
    Card(Modifier.fillMaxWidth().padding(8.dp)) {
        Text(pesan, Modifier.padding(12.dp))
    }
}

KartuPesan only uses general Compose APIs, so it compiles for Android, desktop, and web at once. Your design system from episode 6 can be used across targets with almost no changes.

Platform Boundaries

Parts that touch platform APIs — cameras, sensors, the Android view framework — still require expect/actual. For UI, Compose Multiplatform provides cross-platform versions of many components, but some Android-specific features still need that boundary.

Limitations and Practical Use Cases

When It Fits

Compose Multiplatform is best suited for: applications with large shared business logic across targets, internal tools like dashboards and admin panels, and teams that already master Kotlin and Compose. Shared UI code meaningfully cuts maintenance costs.

When It Doesn't Yet Fit

For iOS with a consumer target that wants a full native experience, the iOS platform is still maturing. For web that heavily depends on SEO and full accessibility, traditional web frameworks remain a better fit. Evaluate these boundaries before committing to a target.

Closing

Episode 17 explored beyond Android: the Compose Multiplatform project structure with commonMain and expect-actual, running applications on desktop with run and on web with wasmJsBrowserRun, sharing UI components across targets, and the limitations and practical use cases where Compose Multiplatform benefits most.

Key takeaways:

  • Compose Multiplatform brings Compose to desktop, web, and iOS.
  • Shared code lives in commonMain, platform-specific code via expect and actual.
  • ./gradlew :composeApp:run runs desktop, wasmJsBrowserRun for web.
  • Composables with general APIs can be used across targets.
  • Anything touching the platform must go through expect and actual.
  • Evaluate the maturity of each target before committing.

In episode 18 we will discuss custom layouts and modifiers — creating custom layout composables, advanced modifiers and pointer input, reusable UI primitives, and building complex components from scratch.

Learn Jetpack Compose - Desktop, Web, & Multiplatform | Learn Jetpack Compose