Expo UI in SDK 55: Jetpack Compose now available for React Native apps

ProductReact NativeDevelopment6 minutes read

Kudo Chien

Kudo Chien

Engineering

Nishan Bende

Nishan Bende

Engineering

Aleksander Mikucki

Aleksander Mikucki

Engineering

Expo UI in SDK 55 brings Jetpack Compose to beta and aligns SwiftUI APIs with Apple's conventions, so your native framework knowledge transfers directly.

Expo UI in SDK 55: Jetpack Compose now available for React Native apps

Expo UI brings SwiftUI and Jetpack Compose directly into your React Native app. Instead of reimplementing native components in JavaScript, it exposes the real thing — the same components, behavior, and platform polish that native developers get.

In SDK 54, we introduced Expo UI with SwiftUI support and an early alpha for Jetpack Compose. Since then, developers have been building with it — and we used Expo UI as the foundation for expo-widgets, which validated the approach for real production use. But Jetpack Compose support was still in alpha, and we hadn't tested it against a complete app yet.

SDK 55 addresses both. Jetpack Compose is now in beta with enough Material Design 3 components to build a complete app, and SwiftUI APIs have been reworked to closely match Apple's; so your existing knowledge of either framework transfers directly.

Why this matters

Apple and Google continue to invest heavily in SwiftUI and Jetpack Compose, and many of the newest APIs and components arrive there first. Reimplementing them in JavaScript is a lot of work that's hard to keep up with.

Expo UI takes a different approach: expose the native frameworks directly. You get new platform features as they ship, and because the API surface follows SwiftUI and Jetpack Compose conventions, any developer (or AI) that already knows those frameworks can write Expo UI code without learning something new.

Jetpack Compose: from alpha to beta

To test whether the Compose APIs were ready for real use, we built a complete app called WikiReader (a clone of @nsh07's original) using only Expo UI components. We wanted to find out what was missing and where the rough edges were.

The app uses Material Design 3 components throughout — Card, LazyColumn, ListItem, DockedSearchBar, ModalBottomSheet, and more. We added each component as the app needed it. Every component had to earn its place by solving a real problem in the app.

Here's what the settings screen looks like in Expo UI with Jetpack Compose:

Code
import { useState } from "react";
import { useColorScheme } from "react-native";
import { Host, Switch, Icon, ListItem, LazyColumn } from "@expo/ui/jetpack-compose";
import { clip, Shapes } from "@expo/ui/jetpack-compose/modifiers";
export default function SettingsScreen() {
const colorScheme = useColorScheme() ?? "light";
const [wifi, setWifi] = useState(true);
const [bluetooth, setBluetooth] = useState(false);
const [darkMode, setDarkMode] = useState(false);
return (
<Host style={{ flex: 1 }} colorScheme={colorScheme}>
<LazyColumn
verticalArrangement={{ spacedBy: 2 }}
contentPadding={{ start: 16, end: 16, top: 8, bottom: 16 }}
>
<ListItem headline="Wi-Fi" supportingText="Connected" modifiers={[clip(Shapes.RoundedCorner({ topStart: 12, topEnd: 12 }))]}>
<ListItem.Leading>
<Icon source={require("../../assets/icons/wifi.xml")} tintColor="#1d1b20" />
</ListItem.Leading>
<ListItem.Trailing>
<Switch value={wifi} onValueChange={setWifi} />
</ListItem.Trailing>
</ListItem>
<ListItem headline="Bluetooth" supportingText="Off">
<ListItem.Leading>
<Icon source={require("../../assets/icons/bluetooth.xml")} tintColor="#1d1b20" />
</ListItem.Leading>
<ListItem.Trailing>
<Switch value={bluetooth} onValueChange={setBluetooth} />
</ListItem.Trailing>
</ListItem>
<ListItem headline="Dark mode" modifiers={[clip(Shapes.RoundedCorner({ bottomStart: 12, bottomEnd: 12 }))]}>
<ListItem.Leading>
<Icon source={require("../../assets/icons/dark_mode.xml")} tintColor="#1d1b20" />
</ListItem.Leading>
<ListItem.Trailing>
<Switch value={darkMode} onValueChange={setDarkMode} />
</ListItem.Trailing>
</ListItem>
</LazyColumn>
</Host>
);
}

If you've used Jetpack Compose, the component names and structure should look familiar — LazyColumn with arrangement and padding, modifier chains, ListItem with leading and trailing content. In Compose, you'd pass these as composable lambda parameters. In Expo UI, we use React's compound component pattern (ListItem.Leading, ListItem.Trailing) to express the same layout in JSX.

We also aligned the modifier system. Jetpack Compose has its own modifier chain, and we brought that to JSX in the same style as @expo/ui for SwiftUI, so modifiers work consistently across both platforms:

Code
<Box modifiers={[size(100, 100), background(Color.android.dynamic.primaryContainer)]}>
<Text modifiers={[padding(16)]}>Hello from Compose</Text>
</Box>

This includes scoped modifiers: Row and Column get their own specific options like weight and matchParentSize, just like in Compose. Learn more about modifiers.

We also added an Icon component that natively renders Material Symbols XML vector drawables using Material Symbols as XML drawables is a common practice in Jetpack Compose development. You download icons from Material Symbols as Android drawable XML files and reference them directly:

Code
<Icon source={require('./path/to/symbol.xml')} />

If downloading individual XML files feels like extra work, try asking your AI agent to generate them for you. It worked well for our use case — the AI created both the Expo UI code and the icon XML files together.

We don't aim to wrap every Material Design 3 component. We added what the WikiReader clone needed and will keep expanding based on demand. Thank you to all the external contributors who helped add these components.

Learn more from @expo/ui/jetpack-compose documentation.

SwiftUI: now it feels like SwiftUI

In SDK 55, we've renamed and restructured SwiftUI components to match their SwiftUI counterparts. DateTimePicker is now DatePicker, Switch is now Toggle, and CircularProgress is now ProgressView. If you've worked with SwiftUI before, the component names, modifier names, and overall structure should feel familiar. When you look something up in Apple's documentation, it maps directly to Expo UI; so you can follow Apple's documentation directly, skip learning a translation layer, and AI tools can generate correct code from their existing training data.

Since we can't cover every SwiftUI view and modifier, we've also made Expo UI extensible. You can create your own custom SwiftUI views and modifiers for anything we don't cover yet.

The hot-chocolate showcase app has been updated to SDK 55 and the latest APIs. Check it out for a complete example of building with SwiftUI in Expo.

Learn more from @expo/ui/swift-ui documentation

Building with AI

One of the practical advantages of aligning with native frameworks is how well it works with AI.

Because Expo UI follows SwiftUI and Jetpack Compose conventions, AI tools already have deep knowledge of the patterns. We leaned into this by adding skills to expo/skills that teach AI assistants the Expo UI specifics, and built expo-mcp for tighter integration.

The workflow: upload a screenshot or describe what you want, and the AI generates Expo UI code for both SwiftUI and Jetpack Compose using patterns it already knows. Try this prompt today:

Build an Android Settings-style screen using @expo/ui/jetpack-compose components (Column, Row, Switch, Slider) with Material Symbols for row icons, featuring grouped sections (Network, Display, Sound, Privacy) with toggle switches and a brightness slider.

What's next

We're working toward universal components in Expo UI: a shared component API that works across SwiftUI and Jetpack Compose (and potentially on web as well).

But right now, we'd love your feedback on SDK 55. Try building an app with Expo UI — whether it's the @expo/ui/swift-ui or @expo/ui/jetpack-compose side — and tell us how it goes. What components are missing? What feels off? Your input directly shapes what we build next.

Expo UI
SDK 55

Accelerate building apps with Expo and AI

Learn more