JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
16.35k stars 1.18k forks source link

Use HTML tag in Compose for web / Kotlin Wasm #3172

Closed sz21106677 closed 2 months ago

sz21106677 commented 1 year ago

Is there any existing method to insert HTML native tags in Compose?

alexzhirkevich commented 1 year ago

You probably can add html with absolute position next to the compose render canvas and set its position from compose wasm code

alexzhirkevich commented 1 year ago

Can be a great enhancement to have an HTMLView wasm composable that will allow to seamlessly use compose-html inside of it

eymar commented 1 year ago

There is no such API out of a box for now.

sc941737 commented 1 year ago

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
    }
}
okushnikov commented 4 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

Jacko760 commented 1 month ago

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>

KmpApp2

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")

Skaldebane commented 1 month ago

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.