Compose Multiplatform UI library for WebAssembly/JS target - declarative framework for sharing UIs across multiple platforms with Kotlin.
—
Window management in Compose Multiplatform for WASM/JS centers around the CanvasBasedWindow function, which creates the main application window that renders to an HTML5 Canvas element. This approach provides full control over the rendering surface while integrating seamlessly with web browsers.
The primary function for creating WASM/JS applications.
@OptIn(ExperimentalComposeUiApi::class)
fun CanvasBasedWindow(
canvasElementId: String? = null,
title: String = "Compose Application",
content: @Composable () -> Unit
)Parameters:
canvasElementId: ID of the HTML canvas element to render into. If null, uses default "ComposeTarget"title: Window title (affects browser tab title)content: Composable content to display in the windowUsage:
@OptIn(ExperimentalComposeUiApi::class)
fun main() {
CanvasBasedWindow("MyCanvas") {
MaterialTheme {
Text("Hello WASM!")
}
}
}The HTML document must contain a canvas element with the specified ID:
<!DOCTYPE html>
<html>
<head>
<title>My Compose App</title>
<meta charset="UTF-8">
</head>
<body>
<canvas id="MyCanvas"></canvas>
<script src="your-app.js"></script>
</body>
</html>@OptIn(ExperimentalComposeUiApi::class)
fun main() {
// Optional: Configure resources before window creation
configureWebResources {
resourcePathMapping { path -> "./$path" }
}
// Create the main application window
CanvasBasedWindow(
canvasElementId = "ComposeTarget",
title = "My Application"
) {
// Your application content
App()
}
}Default Behavior:
CanvasBasedWindow("ComposeTarget") { /* content */ }Custom Canvas ID:
CanvasBasedWindow("myCustomCanvas") { /* content */ }Auto-Detection (null ID):
CanvasBasedWindow(canvasElementId = null) { /* content */ }
// Uses default "ComposeTarget" IDThe title parameter affects:
CanvasBasedWindow(
canvasElementId = "app",
title = "My WASM Application - ${BuildConfig.VERSION}"
) {
// Application content
}All window management functions require the experimental API opt-in:
@file:OptIn(ExperimentalComposeUiApi::class)
import androidx.compose.ui.ExperimentalComposeUiApiThis annotation indicates that WASM support is experimental and APIs may change.
The canvas element receives these properties:
Style the canvas element for proper display:
#ComposeTarget {
width: 100vw;
height: 100vh;
display: block;
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
overflow: hidden;
}Canvas Not Found:
Error: Canvas element with ID 'ComposeTarget' not foundWASM Initialization Failure:
Error: Failed to instantiate WebAssembly moduleResource Loading Issues:
Error: Failed to load application resourcesCanvas Detection:
// Check if canvas exists before creating window
val canvas = document.getElementById("ComposeTarget")
if (canvas == null) {
console.error("Canvas element not found!")
return
}
CanvasBasedWindow("ComposeTarget") { /* content */ }Console Logging:
fun main() {
console.log("Starting WASM application...")
CanvasBasedWindow("ComposeTarget") {
console.log("Window content initialized")
App()
}
}DisposableEffect for manual cleanup@Composable
fun App() {
DisposableEffect(Unit) {
val cleanup = { /* cleanup code */ }
onDispose { cleanup() }
}
// App content
}Canvas automatically receives and translates:
Access browser APIs from window content:
@Composable
fun BrowserIntegration() {
LaunchedEffect(Unit) {
// Access browser window
val title = window.document.title
// Modify browser state
window.history.pushState(null, "", "/new-route")
// Use browser APIs
val userLanguage = window.navigator.language
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-compose-ui--ui-wasm-js