Back to Tutorials
Expo SDK 56

Build a Native Settings Screen with Expo UI

Expo UI is now production-ready in SDK 56. Here is a practical way to use @expo/ui universal components for a settings screen that feels closer to SwiftUI on iOS and Jetpack Compose on Android.

June 1, 2026 12 min read Paddy B
Expo UI Expo SDK 56 React Native SwiftUI Jetpack Compose

The short version

Use @expo/ui when you want real platform primitives for common app surfaces. In SDK 56, Expo says the SwiftUI and Jetpack Compose APIs are stable, and universal components let you build shared interfaces from one React component tree.

Settings screens are a good place to start. They are mostly lists, text, switches, buttons, sliders, and small sections. That maps neatly to Expo UI without forcing your entire app to move away from normal React Native views.

Why Expo UI matters now

Expo UI is not another JavaScript recreation of native controls. The package exposes native UI toolkits to React Native: SwiftUI on iOS and Jetpack Compose on Android. The universal API gives you a shared import path for common components, while the platform-specific APIs are there when you need to lean into one platform.

In SDK 56, Expo UI moved from promising experiment to production-ready tool. Expo also added it to the default project template and made it available in Expo Go, which makes it much easier to try before you commit to it.

Use it surgically first

You do not need to rewrite the whole app. Start with a contained screen: settings, preferences, account controls, onboarding choices, or any place where native controls make the app feel more at home.

1. Install Expo UI

In an Expo SDK 56 project, install the package with Expo so the version matches your SDK.

npx expo install @expo/ui

If you are starting fresh, create a new SDK 56 app first. New Expo apps include Expo UI in the default template, but the install command is still the right move when you are adding it to an existing app.

npx create-expo-app@latest native-settings cd native-settings npx expo install @expo/ui

2. Wrap native UI with Host

The important root component is Host. It hosts your universal Expo UI subtree. On iOS and Android, the content renders through the platform-native host. On web, it falls back to React Native/web behavior for the universal layer.

import { Host, Column, Text, Button } from "@expo/ui"; export function TinyExpoUiExample() { return ( <Host style={{ flex: 1 }}> <Column spacing={12} alignment="center"> <Text>Native settings are coming together.</Text> <Button label="Save" onPress={() => {}} /> </Column> </Host> ); }

Keep Host as the boundary around the section you want Expo UI to own. Outside that boundary, you can keep using normal React Native components, Expo Router layouts, and your existing design system.

3. Build the settings screen

Here is a practical settings screen using universal components. The exact component surface will keep growing, so this sticks to the documented universal primitives: sectioned layout, readable labels, and state that stays in React.

import { useState } from "react"; import { Host, ScrollView, Column, Row, Text, Button, Switch, Slider, List, ListItem, } from "@expo/ui"; export default function SettingsScreen() { const [pushEnabled, setPushEnabled] = useState(true); const [analyticsEnabled, setAnalyticsEnabled] = useState(false); const [textScale, setTextScale] = useState(1); return ( <Host style={{ flex: 1 }} colorScheme="dark"> <ScrollView> <Column spacing={20} style={{ padding: 20 }}> <Column spacing={6}> <Text textStyle={{ fontSize: 28, fontWeight: "700" }}> Settings </Text> <Text textStyle={{ color: "#94a3b8" }}> Native controls backed by SwiftUI and Jetpack Compose. </Text> </Column> <List> <ListItem supportingText="Product updates and useful reminders" trailing={ <Switch value={pushEnabled} onValueChange={setPushEnabled} /> }> Push notifications </ListItem> <ListItem supportingText="Help improve the app without sharing personal content" trailing={ <Switch value={analyticsEnabled} onValueChange={setAnalyticsEnabled} /> }> Share usage analytics </ListItem> </List> <Column spacing={10}> <Row alignment="center" spacing={12}> <Text textStyle={{ fontWeight: "600" }}>Text size</Text> <Text textStyle={{ color: "#94a3b8" }}> {textScale.toFixed(1)}x </Text> </Row> <Slider value={textScale} min={0.8} max={1.4} step={0.1} onValueChange={setTextScale} /> </Column> <Button label="Save preferences" onPress={() => { console.log({ pushEnabled, analyticsEnabled, textScale }); }} /> </Column> </ScrollView> </Host> ); }

The state is ordinary React state. The difference is the presentation layer: native controls do more of the platform work for you. For text styling, use textStyle; for sliders, use min, max, and step.

4. Mix React Native and Expo UI carefully

A good Expo UI screen does not need to be pure Expo UI. Keep product-specific layout in React Native when that is easier, then use Expo UI where native primitives are the win.

import { View } from "react-native"; import { Host, Button, Switch, Row, Text } from "@expo/ui"; export function NotificationRow() { return ( <View style={{ padding: 16, borderRadius: 12 }}> <Host matchContents> <Row spacing={12} alignment="center"> <Text>Weekly digest</Text> <Switch value onValueChange={() => {}} /> <Button label="Preview" onPress={() => {}} /> </Row> </Host> </View> ); }

matchContents is useful for small embedded native UI islands. For a whole screen, keep Host style={{ flex: 1 }} so the native subtree gets the space it needs.

5. Platform notes

  • iOS: Expo UI maps to SwiftUI-backed components, so settings and form-style interfaces can feel much closer to system UI.
  • Android: Expo UI maps to Jetpack Compose-backed components, which is the modern Android UI toolkit.
  • Web: Universal components can run on web, but Expo describes web support as more experimental. Test web separately and keep fallbacks simple.
  • Expo Go: Expo UI is available in Expo Go in SDK 56, which makes prototyping easier. Still test production screens in development builds before release.

When to use Expo UI

Expo UI is a strong fit for surfaces where users expect platform-native behavior:

  • Settings and account screens.
  • Preference forms with switches, sliders, buttons, and pickers.
  • Native-feeling sheets and simple controls.
  • Replacing common community UI packages with Expo-managed primitives.

Stick with normal React Native views for custom brand-heavy layouts, animation-heavy surfaces, and screens where your existing component system is already doing the job.

Final checklist

  • Install @expo/ui with npx expo install.
  • Wrap native UI islands or screens with Host.
  • Start with one contained settings screen before migrating larger surfaces.
  • Test iOS, Android, and web separately because the universal layer still depends on platform behavior.
  • Use native Expo UI controls where they improve the experience, not just because they are new.
Support tutorials