Compose Multiplatform UI
Use this skill for Compose Multiplatform screens, shared UI architecture, Android/iOS/Desktop/Web entry points, Compose resources, navigation, state modeling, previews, performance, accessibility, and UI tests.
Context First
Before changing UI:
- Identify whether the project shares UI across all client platforms or only some.
- Read the existing screen, route, ViewModel/state holder, theme, resources, and navigation convention.
- Verify Compose Multiplatform and Compose compiler setup before adding APIs or dependencies.
- Preserve existing MVI, MVVM, Redux, Decompose, Voyager, or platform-native navigation if coherent.
UI Boundary
Recommended split for shared Compose UI:
- Route: obtains state holder, collects state/effects, wires platform navigation, snackbar, permissions, and lifecycle.
- Screen: stateless renderer with state plus callbacks.
- Leaf composables: small renderers with only visual-local state such as scroll, focus, expansion, or animation.
- State holder/ViewModel: owns business state transitions, async work, repositories, and one-shot effects.
Do not run network calls from composables. Do not store controllers, lambdas, MutableState, Android Context, UIKit objects, or platform handles in durable screen state.
Platform Entry Points
Use the local project convention. Common patterns:
- Android: app module calls
setContent { App() } from an Activity.
- iOS shared UI: expose a
ComposeUIViewController { App() } facade from an iOS source set.
- Desktop: desktop app module opens a Compose window and calls shared UI.
- Web/Wasm: web app module owns bootstrap and calls shared UI.
Do not put Android application packaging or launch configuration inside the shared KMP library module for AGP 9+ work.
Resources
- Use Compose Multiplatform resources for shared strings, images, and files when UI is shared.
- Use Android resources only for Android app-shell concerns or Android-specific integration.
- Treat
group and package changes carefully: resource accessor namespaces can change.
- Keep strings localizable and avoid hardcoded user-facing copy in composables.
State And Effects
- Model editable raw input separately from parsed/validated business values.
- Keep state immutable and equality-friendly.
- Derive values instead of storing duplicates when possible.
- Use one-shot effects for navigation, snackbar, share, permission request, and platform intents.
- Preserve previous content during refresh unless product requirements say otherwise.
Performance And Accessibility
- Use a Measure -> Diagnose -> Fix -> Verify loop. Do not optimize from intuition when a release-mode measurement path is available.
- First fix state shape and read boundaries; API-level micro-optimizations come second.
- Pass narrow props to leaf composables.
- Key lazy items by stable domain IDs.
- For lazy layouts, verify stable keys, meaningful content types, and item composable skippability before changing prefetch or cache windows.
- For recomposition issues, inspect state read phase, stability, Compose compiler reports, and runtime recomposition evidence before rewriting UI.
- Measure startup and frame timing in release-like Android builds when Android is an affected target; debug Compose performance is not representative.
- Add semantics for icon-only controls and custom components.
- Keep touch targets and text scaling usable across platforms.
- Avoid platform-specific assumptions in shared UI unless guarded by source set or interface.
- On iOS, verify accessibility tree synchronization mode when accessibility behavior or performance is in scope.
- Use
testTag/accessibility identifiers intentionally when native XCTest or platform automation must find shared Compose UI.
Testing
- Test state holders and reducers in
commonTest.
- Test validators and formatters as pure functions.
- Use Compose UI tests in the source set supported by the project and current Compose version.
- For Compose Multiplatform UI tests, verify current dependency/source-set setup in official docs before adding
ui-test dependencies.
- For iOS accessibility-sensitive work, consider XCTest
performAccessibilityAudit when the platform test harness exists.
- For platform entry wiring, run the platform app or screenshot path where practical.