ComposeMultiplatformWebview
Compose Multiplatform Webview library to support webview natively accross all Platform.
Install / Use
/learn @saral-apps/ComposeMultiplatformWebviewREADME
Compose Multiplatform Native WebView
A powerful native WebView integration for Compose Multiplatform that provides seamless web content rendering across Android, iOS, Desktop (Windows/macOS), and JVM platforms. Built with native platform APIs for superior performance, authentic user experience, and zero external dependencies.

🌟 Why Choose Compose Native WebView?
True Native Integration – Leverages each platform's native WebView components: Android WebView, iOS WKWebView, Windows WebView2 (Chromium), and macOS WKWebView for authentic platform behavior.
Universal Cross-Platform Support – Single API that works seamlessly across Android, iOS, Windows, macOS, and Linux (community-supported).
Zero Bundled Dependencies – No embedded browsers or heavy dependencies. Uses the web rendering technology already present on each platform.
Production-Ready Performance – Battle-tested in real-world applications with native-level performance and memory efficiency.
Compose-First Design – Idiomatic Kotlin Multiplatform API built specifically for Compose developers with reactive state management.
Enterprise-Grade Security – Inherits security features and automatic updates from each platform's native WebView implementation.
✨ Key Features
Platform Coverage
- ✅ Android – Native Android WebView integration
- ✅ iOS – Native WKWebView implementation
- ✅ Windows – WebView2 (Edge Chromium) via JNA
- ✅ macOS – WKWebView (Apple Silicon & Intel) via JNA
- ✅ Desktop JVM – Cross-platform desktop support
- 🔄 Linux – Community contributions welcome
Core Capabilities
- Native Platform WebViews – Direct integration with system WebView components
- Full JavaScript Interop – Execute JavaScript and communicate bidirectionally
- Advanced Navigation Controls – Complete URL management, history, and navigation blocking
- Reactive State Management – Track loading state, URLs, titles, and navigation events
- Security Controls – JavaScript toggle, file access permissions, and navigation filtering
- Lifecycle Management – Proper creation, disposal, and resource management
- Modern Web Standards – Full HTML5, CSS3, ES6+, WebGL, WebAssembly support
- Compose-Optimized API – Idiomatic composable functions with state hoisting
📦 Installation
Add the dependency to your build.gradle.kts:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("com.saralapps:composemultiplatformwebview:0.1.4")
}
}
}
Platform-Specific Requirements
Android:
- Minimum SDK: 21 (Android 5.0 Lollipop)
- Android WebView is included in the system
iOS:
- iOS 11.0+
- WKWebView is included with iOS
Windows (x64):
- Windows 10 version 1803 or later
- Microsoft Edge WebView2 Runtime (pre-installed on Windows 11, downloadable for Windows 10)
macOS:
- macOS 11.5 or later
- WKWebView included with system frameworks
Linux:
- Community-supported implementations available
- Requires GTK WebKitGTK or Qt WebEngine
🚀 Quick Start
Basic WebView (Simplest Approach)
import com.saralapps.composemultiplatformwebview.PlatformWebView
@Composable
fun App() {
PlatformWebView(
url = "https://kotlinlang.org",
modifier = Modifier.fillMaxSize()
)
}
WebView with State Management
@Composable
fun WebViewWithState() {
val webViewState = rememberPlatformWebViewState(
url = "https://github.com",
javaScriptEnabled = true,
allowsFileAccess = true
)
PlatformWebView(
state = webViewState,
modifier = Modifier.fillMaxSize(),
onUrlChanged = { newUrl ->
println("Navigated to: $newUrl")
}
)
}
Interactive Browser with Navigation
@Composable
fun InteractiveBrowser() {
var currentUrl by remember { mutableStateOf("https://example.com") }
var isLoading by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize()) {
// Navigation bar
Row(
modifier = Modifier.fillMaxWidth().padding(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
TextField(
value = currentUrl,
onValueChange = { currentUrl = it },
modifier = Modifier.weight(1f),
placeholder = { Text("Enter URL") },
singleLine = true
)
Button(
onClick = { /* Trigger navigation */ },
enabled = !isLoading
) {
Text("Go")
}
}
// Loading indicator
if (isLoading) {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth()
)
}
// WebView
PlatformWebView(
url = currentUrl,
modifier = Modifier.weight(1f),
javaScriptEnabled = true,
onUrlChanged = { newUrl ->
currentUrl = newUrl
isLoading = false
},
onNavigating = { url ->
isLoading = true
true // Allow navigation
}
)
}
}
Handling WebView Availability
@Composable
fun WebViewWithFallback() {
PlatformWebView(
url = "https://example.com",
modifier = Modifier.fillMaxSize(),
onUnavailable = { availability ->
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
when (availability) {
is WebViewAvailability.NotInstalled -> {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("WebView not available on this device")
Button(onClick = { /* Handle installation */ }) {
Text("Install WebView2")
}
}
}
is WebViewAvailability.Error -> {
Text("Error: ${availability.message}")
}
else -> {
Text("WebView unavailable")
}
}
}
}
)
}
🎯 Core API Components
PlatformWebViewState
Manages the internal state and configuration of the WebView:
val webViewState = rememberPlatformWebViewState(
url = "https://example.com",
javaScriptEnabled = true,
allowsFileAccess = false,
onNavigating = { url ->
// Return true to allow, false to block navigation
url.startsWith("https://")
}
)
Parameters:
url: String?- Initial URL to load (optional)javaScriptEnabled: Boolean- Enable/disable JavaScript execution (default:true)allowsFileAccess: Boolean- Allow/deny local file access (default:true)onNavigating: ((String) -> Boolean)?- Navigation interception callback
PlatformWebView Composable
Two variants available for different use cases:
1. State-Based Variant (Recommended)
Best for complex scenarios requiring state management:
@Composable
fun PlatformWebView(
state: PlatformWebViewState,
modifier: Modifier = Modifier,
placeholderColor: Color = Color.White,
onUrlChanged: ((String) -> Unit)? = null,
onCreated: (() -> Unit)? = null,
onDisposed: (() -> Unit)? = null,
onUnavailable: @Composable ((WebViewAvailability) -> Unit)? = null
)
2. Direct URL Variant (Simple)
Perfect for straightforward WebView integration:
@Composable
fun PlatformWebView(
url: String,
modifier: Modifier = Modifier,
javaScriptEnabled: Boolean = true,
allowsFileAccess: Boolean = true,
placeholderColor: Color = Color.White,
onUrlChanged: ((String) -> Unit)? = null,
onNavigating: ((String) -> Boolean)? = null,
onCreated: (() -> Unit)? = null,
onDisposed: (() -> Unit)? = null,
onUnavailable: @Composable ((WebViewAvailability) -> Unit)? = null
)
Common Parameters Reference
| Parameter | Type | Description |
|-----------|------|-------------|
| modifier | Modifier | Compose modifier for layout and styling |
| placeholderColor | Color | Background color during WebView initialization |
| onUrlChanged | ((String) -> Unit)? | Callback triggered when URL changes |
| onNavigating | ((String) -> Boolean)? | Pre-navigation callback; return false to block |
| onCreated | (() -> Unit)? | Callback when WebView is successfully created |
| onDisposed | (() -> Unit)? | Callback when WebView is disposed |
| onUnavailable | @Composable ((WebViewAvailability) -> Unit)? | Composable shown when W
