
Share UI code across native and semantic HTML, with adaptive sizing, pane layouts, replaceable design systems, real HTML semantics and optional Material components for responsive, themeable apps.
Share your Compose code across native apps and semantic HTML, with responsive layouts on every platform.
The 0.9.0 demo shares 90.9% of its application source across targets. Built-in sizing, wrapping and adaptive pane APIs let the same feature respond to phone, tablet and desktop space. What the sharing measurement includes.
Documentation · Shopping demo · Playground · API reference
Domposable is a Kotlin Multiplatform UI library with optional integration helpers, built on Compose. Feature teams write regular composables with shared components, modifiers and adaptive layouts. An installed design system provider renders those calls as Compose UI on native targets or semantic HTML on Kotlin/JS. The primary web target is HTML; it does not require Wasm.
[!IMPORTANT] The HTML target is a client-rendered single-page application (SPA), built on Compose HTML. Domposable does not provide server-side rendering (SSR). Route URLs and static hosting entry pages do not render feature content on the server. Hosts such as Kobweb may offer their own static pre-rendering; that is a separate integration, not Domposable SSR.
The supported baseline uses stable Compose Multiplatform core; optional design mappings do not force an alpha core upgrade. See tested versions and upgrade policy.
Your application owns its dependencies and state. Pass an existing ViewModel, use your DI container's Compose integration, or keep state in a composable. Koin and Metro use the same generated entry API; existing frameworks can reuse the generator with their own annotations and hosts.
Build your own visual language with shared layouts and controls, theme an existing provider, or add custom native/HTML renderers and modifier decorations without changing Domposable. Custom design systems keep feature code common across platforms.
[!NOTE] This README describes
main. Choose a published version from Releases. Before 1.0, minor releases may change APIs; see the migration guide when upgrading.
Add mavenCentral() and google() to your repositories, then replace <released-version> with a version from Releases.
val domposableVersion = "<released-version>"
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.samuolis.domposable:domposable-design-material:$domposableVersion")
// Optional: adaptive layout helpers.
implementation("io.github.samuolis.domposable:domposable-adaptive:$domposableVersion")
}
}
}The Material artifact includes the shared UI API and default platform providers. See the installation guide and tested toolchain for Compose plugins and target setup.
import androidx.compose.runtime.Composable
import io.github.samuolis.domposable.foundation.*
import io.github.samuolis.domposable.material.DomposableMaterialTheme
import io.github.samuolis.domposable.ui.*
@Composable
fun ContactsScreen(onAddContact: () -> Unit) {
DomposableColumn(
modifier = DomposableModifier.padding(16.dp),
gap = 12.dp,
) {
DomposableText("Contacts", style = DomposableTextStyle.Title)
DomposableButton("Add contact", onAddContact)
}
}
@Composable
fun App(onAddContact: () -> Unit) {
DomposableMaterialTheme {
ContactsScreen(onAddContact)
}
}Use Android setContent, iOS ComposeUIViewController, a desktop Compose window or Kotlin/JS renderComposable for HTML. The feature and its callbacks stay in commonMain; the host selects the platform's composition environment. An optional experimental Wasm host is available for Compose UI comparisons.
Platform entry-point examples →
Each Domposable component reads the nearest theme's typed renderer and forwards its values, callbacks and ordered modifier chain. The renderer creates the platform control and connects events back to the feature.
flowchart TB
Feature[Shared feature composable] --> Components[Domposable component calls]
Components --> Provider[Installed theme and component provider]
Provider --> Native[Compose UI: Android, iOS, desktop, Wasm]
Provider --> HTML[Semantic HTML and CSS: Kotlin/JS]The same feature can use different element structures and styling on each platform. Set theme colors, typography, shapes and component styles, or replace a renderer for a different control implementation. Component use requires no application KSP setup or navigation registry.
Brand the standard controls once; every argument is optional:
DomposableMaterialTheme(
colors = brandColors,
styles = DomposableComponentStyles(
button = DomposableButtonAppearance(shape = DomposableShape.Circle),
),
) {
FeatureScreen()
}Use DomposableTheme.styles.button.copy(...) for a local override. Nested themes inherit their enclosing brand values. Styles are composition-scoped, so different parts of an app can use different brands.
Custom cards are shared composition too: use DomposableBox for overlapping image/content layers, a portable gradient for the scrim, and the same theme for controls. Application CSS is an escape hatch for a custom renderer, rather than a requirement for every custom layout. Build a card without CSS · Card and pane demo.
Understand the API → · Customize a design system → · Build adaptive layouts →
| Your app | Adopt | Keep in your app |
|---|---|---|
| Starting a shared UI | Material provider, components and adaptive helpers | Models, DI and application behaviour |
| Has a design system | Theme defaults and thin adapters behind existing component names | Brand tokens, product layouts and custom controls |
| Has Navigation 3 or another router | Optional entry display, pane and browser helpers | Back stack, entry decorators, route identity and URL policy |
| Has screen annotations and codegen | Optional KSP function driver | Annotation contract, DI bindings and generated host templates |
Components and adaptive helpers do not depend on the screen registry, navigator or ViewModel adapter. KSP is optional. Your app can use Koin, Metro, another DI container or no DI.
Existing Compose UI widgets cannot run inside an HTML composition. Sharing a feature requires portable component calls or your own native/HTML adapters; this is more than changing imports. Migrate one feature at a time →
| Target | Rendering | Support |
|---|---|---|
| Android, API 24+ | Compose UI + Material 3 | Supported |
| iOS arm64 and arm64 simulator | Compose UI + Material 3 | Supported |
| Web, Kotlin/JS | Semantic DOM + CSS + browser controls | Supported |
| JVM desktop | Compose UI + Material 3 | Experimental |
| Web, Kotlin/Wasm | Compose UI in the browser | Experimental |
HTML and Wasm support optional browser history, hash or path URLs and portable entry-state restoration. HTML collections normally render all keyed items; columns, rows, grids and tables can opt into bounded windowing.
Compatibility, tested versions and platform boundaries →
drawBehind. Web adapters can also attach CSS and attributes directly.| Example | What to explore | Open |
|---|---|---|
| Fieldwork shop | Responsive storefront, product pages, filters, cart and checkout | Live app · Walkthrough |
| Documents and data | Rich inputs, typed choices, forms, disclosure, rich text, charts and interactive tables | Shared source · Recipes |
| Material and expressive catalog | Theme defaults, local appearance overrides, pickers, menus, expressive actions and screen chrome | Live catalog · Shared source · API guide |
| Component playground | Shared controls, theme tokens and renderer customization | Live app · Components |
| HTML / Wasm comparison | The same feature at phone, tablet and desktop widths | Compare |
| Browser routes | Clean paths, deep links and browser navigation | URL example · Routing guide |
| Large collections | Measured lists, horizontal rows, responsive grids and semantic tables | Gallery · Guide |
| Navigation policies | Route overlays, Back previews and live models across root switches | Recipe · Guide |
| Saved root stacks | Independent tabs, restored drafts and caller-owned Navigation 3 scenes | Recipe source · Guide |
The fictional Fieldwork shop shares its catalogue, cart and feature composables. On the web it uses real links and form controls, with product URLs such as /domposable/shop/products/canvas-weekender/.
See the Material catalog for standard and expressive variants, theme configuration and per-component overrides.
The extension example combines a custom label, native drawing and HTML/CSS decoration while keeping counter and input state in shared code.
The modular shopping example separates catalog and checkout into API and implementation modules. Metro injects entry-owned ViewModels, a composition local supplies typed navigation, and optional KSP generates feature entries. The screen guide also shows manual registration and direct Navigation 3 integration.
Use the pieces your application needs. All artifacts use io.github.samuolis.domposable:<artifact>:<released-version>.
| Artifact | Purpose |
|---|---|
domposable-foundation |
Portable values and theme tokens |
domposable-ui |
Shared components, typed renderer contracts and ordered modifiers |
domposable-design-material |
Default native Material and semantic HTML providers |
domposable-adaptive |
Content-sized breakpoints, preferences and pane recipes |
| Artifact | Purpose |
|---|---|
domposable-screens |
Typed registration and entry-owned resources/saveables |
domposable-navigation3 |
Navigation 3 hosts and HTML/Wasm browser history |
domposable-lifecycle-viewmodel |
AndroidX entry ownership and optional state/action helpers |
domposable-ksp |
Generated typed entries and feature entry lists |
| I want to… | Read |
|---|---|
| Install Domposable and set up platform hosts | Getting started |
| Understand components, props, providers and modifiers | How the API works |
| Use shared controls with examples | Components |
| Configure Material 3 and expressive components | Material catalog |
| Adapt a feature to its available space | Adaptive layouts |
| Build or customize a design system | Design systems |
| Add screens, Navigation 3 or generated entries | Screens and navigation |
| Integrate Koin, Metro or Kobweb | Integrations |
| Follow the API/implementation module example | Modular app walkthrough |
| Check supported versions and limitations | Compatibility |
| Compare Wasm input and accessibility | Shared input lab and tested boundaries |
| Browse generated declarations | API reference |
Bug reports and focused contributions are welcome. Start with CONTRIBUTING.md for local setup, validation and maintainer workflows, or open an issue.
PR checks cover ktlint, detekt, Android lint, JVM/Android coverage floors, required binary API checks, packaged consumers, and functional/screenshot tests across native, HTML and Wasm targets. CI keeps reports and captures in GitHub Actions artifacts. API baseline changes need compatibility, migration and version-impact notes.
Apache License 2.0. Copyright 2026 Samuolis.
Share your Compose code across native apps and semantic HTML, with responsive layouts on every platform.
The 0.9.0 demo shares 90.9% of its application source across targets. Built-in sizing, wrapping and adaptive pane APIs let the same feature respond to phone, tablet and desktop space. What the sharing measurement includes.
Documentation · Shopping demo · Playground · API reference
Domposable is a Kotlin Multiplatform UI library with optional integration helpers, built on Compose. Feature teams write regular composables with shared components, modifiers and adaptive layouts. An installed design system provider renders those calls as Compose UI on native targets or semantic HTML on Kotlin/JS. The primary web target is HTML; it does not require Wasm.
[!IMPORTANT] The HTML target is a client-rendered single-page application (SPA), built on Compose HTML. Domposable does not provide server-side rendering (SSR). Route URLs and static hosting entry pages do not render feature content on the server. Hosts such as Kobweb may offer their own static pre-rendering; that is a separate integration, not Domposable SSR.
The supported baseline uses stable Compose Multiplatform core; optional design mappings do not force an alpha core upgrade. See tested versions and upgrade policy.
Your application owns its dependencies and state. Pass an existing ViewModel, use your DI container's Compose integration, or keep state in a composable. Koin and Metro use the same generated entry API; existing frameworks can reuse the generator with their own annotations and hosts.
Build your own visual language with shared layouts and controls, theme an existing provider, or add custom native/HTML renderers and modifier decorations without changing Domposable. Custom design systems keep feature code common across platforms.
[!NOTE] This README describes
main. Choose a published version from Releases. Before 1.0, minor releases may change APIs; see the migration guide when upgrading.
Add mavenCentral() and google() to your repositories, then replace <released-version> with a version from Releases.
val domposableVersion = "<released-version>"
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.samuolis.domposable:domposable-design-material:$domposableVersion")
// Optional: adaptive layout helpers.
implementation("io.github.samuolis.domposable:domposable-adaptive:$domposableVersion")
}
}
}The Material artifact includes the shared UI API and default platform providers. See the installation guide and tested toolchain for Compose plugins and target setup.
import androidx.compose.runtime.Composable
import io.github.samuolis.domposable.foundation.*
import io.github.samuolis.domposable.material.DomposableMaterialTheme
import io.github.samuolis.domposable.ui.*
@Composable
fun ContactsScreen(onAddContact: () -> Unit) {
DomposableColumn(
modifier = DomposableModifier.padding(16.dp),
gap = 12.dp,
) {
DomposableText("Contacts", style = DomposableTextStyle.Title)
DomposableButton("Add contact", onAddContact)
}
}
@Composable
fun App(onAddContact: () -> Unit) {
DomposableMaterialTheme {
ContactsScreen(onAddContact)
}
}Use Android setContent, iOS ComposeUIViewController, a desktop Compose window or Kotlin/JS renderComposable for HTML. The feature and its callbacks stay in commonMain; the host selects the platform's composition environment. An optional experimental Wasm host is available for Compose UI comparisons.
Platform entry-point examples →
Each Domposable component reads the nearest theme's typed renderer and forwards its values, callbacks and ordered modifier chain. The renderer creates the platform control and connects events back to the feature.
flowchart TB
Feature[Shared feature composable] --> Components[Domposable component calls]
Components --> Provider[Installed theme and component provider]
Provider --> Native[Compose UI: Android, iOS, desktop, Wasm]
Provider --> HTML[Semantic HTML and CSS: Kotlin/JS]The same feature can use different element structures and styling on each platform. Set theme colors, typography, shapes and component styles, or replace a renderer for a different control implementation. Component use requires no application KSP setup or navigation registry.
Brand the standard controls once; every argument is optional:
DomposableMaterialTheme(
colors = brandColors,
styles = DomposableComponentStyles(
button = DomposableButtonAppearance(shape = DomposableShape.Circle),
),
) {
FeatureScreen()
}Use DomposableTheme.styles.button.copy(...) for a local override. Nested themes inherit their enclosing brand values. Styles are composition-scoped, so different parts of an app can use different brands.
Custom cards are shared composition too: use DomposableBox for overlapping image/content layers, a portable gradient for the scrim, and the same theme for controls. Application CSS is an escape hatch for a custom renderer, rather than a requirement for every custom layout. Build a card without CSS · Card and pane demo.
Understand the API → · Customize a design system → · Build adaptive layouts →
| Your app | Adopt | Keep in your app |
|---|---|---|
| Starting a shared UI | Material provider, components and adaptive helpers | Models, DI and application behaviour |
| Has a design system | Theme defaults and thin adapters behind existing component names | Brand tokens, product layouts and custom controls |
| Has Navigation 3 or another router | Optional entry display, pane and browser helpers | Back stack, entry decorators, route identity and URL policy |
| Has screen annotations and codegen | Optional KSP function driver | Annotation contract, DI bindings and generated host templates |
Components and adaptive helpers do not depend on the screen registry, navigator or ViewModel adapter. KSP is optional. Your app can use Koin, Metro, another DI container or no DI.
Existing Compose UI widgets cannot run inside an HTML composition. Sharing a feature requires portable component calls or your own native/HTML adapters; this is more than changing imports. Migrate one feature at a time →
| Target | Rendering | Support |
|---|---|---|
| Android, API 24+ | Compose UI + Material 3 | Supported |
| iOS arm64 and arm64 simulator | Compose UI + Material 3 | Supported |
| Web, Kotlin/JS | Semantic DOM + CSS + browser controls | Supported |
| JVM desktop | Compose UI + Material 3 | Experimental |
| Web, Kotlin/Wasm | Compose UI in the browser | Experimental |
HTML and Wasm support optional browser history, hash or path URLs and portable entry-state restoration. HTML collections normally render all keyed items; columns, rows, grids and tables can opt into bounded windowing.
Compatibility, tested versions and platform boundaries →
drawBehind. Web adapters can also attach CSS and attributes directly.| Example | What to explore | Open |
|---|---|---|
| Fieldwork shop | Responsive storefront, product pages, filters, cart and checkout | Live app · Walkthrough |
| Documents and data | Rich inputs, typed choices, forms, disclosure, rich text, charts and interactive tables | Shared source · Recipes |
| Material and expressive catalog | Theme defaults, local appearance overrides, pickers, menus, expressive actions and screen chrome | Live catalog · Shared source · API guide |
| Component playground | Shared controls, theme tokens and renderer customization | Live app · Components |
| HTML / Wasm comparison | The same feature at phone, tablet and desktop widths | Compare |
| Browser routes | Clean paths, deep links and browser navigation | URL example · Routing guide |
| Large collections | Measured lists, horizontal rows, responsive grids and semantic tables | Gallery · Guide |
| Navigation policies | Route overlays, Back previews and live models across root switches | Recipe · Guide |
| Saved root stacks | Independent tabs, restored drafts and caller-owned Navigation 3 scenes | Recipe source · Guide |
The fictional Fieldwork shop shares its catalogue, cart and feature composables. On the web it uses real links and form controls, with product URLs such as /domposable/shop/products/canvas-weekender/.
See the Material catalog for standard and expressive variants, theme configuration and per-component overrides.
The extension example combines a custom label, native drawing and HTML/CSS decoration while keeping counter and input state in shared code.
The modular shopping example separates catalog and checkout into API and implementation modules. Metro injects entry-owned ViewModels, a composition local supplies typed navigation, and optional KSP generates feature entries. The screen guide also shows manual registration and direct Navigation 3 integration.
Use the pieces your application needs. All artifacts use io.github.samuolis.domposable:<artifact>:<released-version>.
| Artifact | Purpose |
|---|---|
domposable-foundation |
Portable values and theme tokens |
domposable-ui |
Shared components, typed renderer contracts and ordered modifiers |
domposable-design-material |
Default native Material and semantic HTML providers |
domposable-adaptive |
Content-sized breakpoints, preferences and pane recipes |
| Artifact | Purpose |
|---|---|
domposable-screens |
Typed registration and entry-owned resources/saveables |
domposable-navigation3 |
Navigation 3 hosts and HTML/Wasm browser history |
domposable-lifecycle-viewmodel |
AndroidX entry ownership and optional state/action helpers |
domposable-ksp |
Generated typed entries and feature entry lists |
| I want to… | Read |
|---|---|
| Install Domposable and set up platform hosts | Getting started |
| Understand components, props, providers and modifiers | How the API works |
| Use shared controls with examples | Components |
| Configure Material 3 and expressive components | Material catalog |
| Adapt a feature to its available space | Adaptive layouts |
| Build or customize a design system | Design systems |
| Add screens, Navigation 3 or generated entries | Screens and navigation |
| Integrate Koin, Metro or Kobweb | Integrations |
| Follow the API/implementation module example | Modular app walkthrough |
| Check supported versions and limitations | Compatibility |
| Compare Wasm input and accessibility | Shared input lab and tested boundaries |
| Browse generated declarations | API reference |
Bug reports and focused contributions are welcome. Start with CONTRIBUTING.md for local setup, validation and maintainer workflows, or open an issue.
PR checks cover ktlint, detekt, Android lint, JVM/Android coverage floors, required binary API checks, packaged consumers, and functional/screenshot tests across native, HTML and Wasm targets. CI keeps reports and captures in GitHub Actions artifacts. API baseline changes need compatibility, migration and version-impact notes.
Apache License 2.0. Copyright 2026 Samuolis.