Closed sz21106677 closed 2 months ago
You probably can add html with absolute position next to the compose render canvas and set its position from compose wasm code
Can be a great enhancement to have an HTMLView
wasm composable that will allow to seamlessly use compose-html inside of it
There is no such API out of a box for now.
You probably can add html with absolute position next to the compose render canvas and set its position from compose wasm code
I've been doing this, works for me for now.
Code sample:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<script src="skiko.js"></script>
</head>
<body>
<div id="root" style="z-index: 1"></div>
<main>
<canvas id="ComposeTarget" width="800" height="600"></canvas>
</main>
</body>
</html>
Main.kt
fun main() {
// Inject viewModel etc.
onWasmReady {
@OptIn(ExperimentalComposeUiApi::class)
CanvasBasedWindow(title = "Sample") {
val someSharedState by viewModel.someSharedState.collectAsState()
// Canvas UI
}
}
renderComposable(rootElementId = "root") {
val someSharedState by viewModel.someSharedState.collectAsState()
// HTML UI
}
}
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.
Code Overview:
JS Main (main.kt):
fun main() { onWasmReady { CanvasBasedWindow("Compose Multiplatform") { App() } } }
JS Main (platform.js.kt):
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.") } }
Common Main (App.kt):
package com.telo.robotics.common
import androidx.compose.runtime.Composable import androidx.compose.ui.window.ApplicationScope
expect fun getPlatform(): Platform
@Composable expect fun PlatformSpecificContent()
// Main entry point for your app @Composable fun App() { ApplicationScope { // Render platform-specific content PlatformSpecificContent() } }
Resources/assets index.html:
<!DOCTYPE html>
Expected Behavior:
The iframe should be rendered beside the row of Icon Buttons in jsMain. The HTML 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. It seems to be an issue specific to the jsMain platform, while other platforms like Android (with WebView) and Desktop render 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.html:internal-html-core-runtime-js:1.7.0")
Hey @Jacko760, found you here as I was looking into this 😅
That approach isn't gonna work, because you're mixing two fundamentally incompatible things (even if both use the Compose Runtime, neither is aware of each other's rendering).
Look at @sc941737's approach, that looks a lot more promising, though you'll have to handle absolute positioning etc... yourself, and it'll be overlaid on top of the canvas, so it's not without drawbacks.
Is there any existing method to insert HTML native tags in Compose?