This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
Extending with Jetpack Compose
Learn how to create custom Jetpack Compose components and modifiers that integrate with Expo UI.
This guide explains how to use the Expo Modules API to create custom Jetpack Compose components and modifiers that integrate with Expo UI.
3 requirements
3 requirements
1.
@expo/ui installedSee Jetpack Compose components in Expo UI for more information.
2.
A custom Expo module contains native code, which Expo Go cannot load. Create a development build of your app.
3.
This guide assumes basic familiarity with the Expo Modules API and Jetpack Compose.
Creating a custom component
Project setup
1
Create a local Expo module in your project:
2
Update your module's android/build.gradle to enable Jetpack Compose and depend on expo-ui. Comments in the following snippet mark the lines you add to the default scaffold:
Creating a Compose view
3
Create your Compose view. It has two parts:
- Props data class: has the
@OptimizedComposePropsannotation, implementsComposeProps, and includes amodifiers: ModifierListfield for themodifiersprop. @Composablecontent function: an extension onFunctionalComposableScopeso it can callModifierRegistry.applyModifiers(...)and renderChildren(...).
4
Register the view in your module using ExpoUIView. This wires your @Composable content into the Expo modules view system and makes it available to JavaScript:
5
Create a wrapper component that connects modifiers with event handling. The createViewModifierEventListener utility enables event-based modifiers like clickable and onVisibilityChanged to work with your custom view:
6
Export the component from your module's entry point:
Using your custom component
Your custom component now works with all built-in Expo UI modifiers:
Creating custom modifiers
You can also create custom modifiers that work with any Expo UI component.
Modifiers are Compose's way to configure layouts for styling, sizing, behavior, and more. Learn more in Android's Compose modifiers documentation.
Native modifier implementation
1
Define your modifier's parameters as an @OptimizedRecord data class. Then write a function that returns a Modifier from those parameters:
compose is a Kotlin extension property on android.graphics.Color? defined in the expo.modules.ui package. Importing it with import expo.modules.ui.compose lets you call params.color.compose to convert the Android Color parsed from JS into the androidx.compose.ui.graphics.Color that Compose APIs (like BorderStroke) expect. It's the same helper Expo UI's built-in modifiers use.
2
Register your modifier with ModifierRegistry in your module definition. Use OnCreate to register and OnDestroy to unregister so the factory does not leak across module reloads:
The register lambda receives the raw map sent from JavaScript, the current ComposableScope (use it for scope-dependent modifiers like weight or align), the AppContext, and an event dispatcher. Most modifiers only need map and convert it via recordFromMap<T>(map).
JavaScript modifier function
3
Create a TypeScript function that builds the modifier config:
4
Export the modifier from your module:
Using custom modifiers
Your custom modifier works with any Expo UI component:
Next steps
Your custom components now work with the built-in modifier system.
Here are some ideas for what to build next:
- Use the built-in Jetpack Compose components that come with Expo UI.
- Build custom modifiers for app-specific styling patterns.
- Wrap third-party Compose libraries for use in React Native.
- Share your components as an npm package for others to use.