Jetpack Compose integration with Expo modules — native Android views, bridging patterns, and module API
Expo Modules API supports Kotlin-first native Android modules. A Module subclass with a definition() body exposes functions, constants, and views to JavaScript — no Java, no ReactPackage registration required.
Define the module, name it, and register functions and views in definition(). The Name() call must match the string used in requireNativeModule() on the JS side.
Expo views extend ExpoView. To host a Compose UI, add a ComposeView as a child and call setContent {} on it. Use ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed to align the Compose lifecycle with the Android view tree. When a prop changes, call setContent {} again to recompose with the new state.
Props are declared with Prop in the module and applied to the subclass. Events use and are registered with in the definition. Fire them by calling the dispatcher with a plain map payload.
definition()ExpoViewEventDispatcherEvents()Compose requires explicit opt-in in the module's build.gradle:
buildFeatures { compose = true }composeOptions { kotlinCompilerExtensionVersion = "<version>" }Config plugins handle Gradle changes in managed workflow — don't edit android/ files manually.
Compose lifecycle is tied to the ViewCompositionStrategy. Use DisposeOnViewTreeLifecycleDestroyed to align with the Android view lifecycle. For subscriptions, use LaunchedEffect inside the composable or OnCreate / OnDestroy in the module definition.
See references/process.md for full Kotlin module code, ComposeView setup, Gradle config, config plugins for Android, testing, debugging, and anti-patterns.