Kotlin/JS Compose Multiplatform: HTML iframe Not Rendering in jsMain
Description:
I’m working on a Kotlin/JS Compose Multiplatform project where I have multiple platform-specific modules: androidMain, commonMain, iosMain, jsMain, and desktopMain. My commonMain includes an entry point (App.kt) using the expect/actual mechanism for multiplatform composition. Inside jsMain, I’ve created a PlatformSpecificContent function to render platform-specific UI elements.
The issue arises when I try to render an iframe inside jsMain. The Compose UI elements (such as Icon Buttons) display correctly, but the iframe I’m trying to insert does not render.
Code Overview:
JS Main (main.kt):
fun main () {
onWasmReady {
CanvasBasedWindow("Compose Multiplatform") {
App()
}
}
}
JS Main (platform.js.kt) :
package com.telo.robotics.jsmain
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
class JSPlatform: Platform {
override val name: String = "compose web using Kotlin/JS"
}
actual fun getPlatform(): Platform = JSPlatform()
@Composable
actual fun PlatformSpecificContent() {
val platform = getPlatform().name
if (platform == "compose web using Kotlin/JS") {
Row {
IconButton(onClick = { /* Handle Home click / }) {
Icon(imageVector = Icons.Filled.Home, contentDescription = "Home", modifier = Modifier.size(24.dp))
}
IconButton(onClick = { / Handle Favorite click / }) {
Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite", modifier = Modifier.size(24.dp))
}
IconButton(onClick = { / Handle Settings click */ }) {
Icon(imageVector = Icons.Filled.Settings, contentDescription = "Settings", modifier = Modifier.size(24.dp))
}
}
Iframe(attrs = {
// Set iframe attributes here
attr("src", "index1.html")
attr("width", "600")
attr("height", "400")
attr("style", "border: none;")
})
} else {
Text("Greeting does not match.")
}
}
CommonMain (app.kt) :
I’m calling this
PlatformSpecificContent()
My index.html:
<!DOCTYPE html>
html lang="en"
head
meta charset="UTF-8"
titleKmpApp2/title
script src="skiko.js"/script
link type="text/css" rel="stylesheet" href="styles.css"
/head
body
div
canvas id="ComposeTarget" width="600" height="800"/canvas
/div
script src="composeApp.js"/script
/body
/html
div
/div
Expected Behavior:
The iframe should be rendered beside the row of Icon Buttons in jsMain. The HTML file content (from index1.html) should appear in the iframe.
Actual Behavior:
Only the row of Compose Icon Buttons is visible, and the iframe does not render at all. I’m unsure how the HTML mapping is being handled in Compose Multiplatform, and this issue seems to be specific to the jsMain platform. For other platforms like Android (which uses WebView) and Desktop (with a different library), the content renders fine.
System Information:
• Xcode Version: (e.g., 14.2)
• macOS Version: (e.g., macOS Monterey 12.4)
• Kotlin Multiplatform Plugin Version: Latest
• Compose Multiplatform Version: Latest
Library used :
implementation("org.jetbrains.compose.htmlinternal html core runtime js1.7.0")
Build.Gradle:
js(IR) {
moduleName = "composeApp"
browser {
commonWebpackConfig {
outputFileName = "composeApp.js"
}
}
binaries.executable()
}
Additional Information:
I’m using the latest versions of Kotlin Multiplatform and Compose Multiplatform. Any insights into how to correctly map HTML iframes within Compose or potential workarounds for this issue would be greatly appreciated.