Expo UI Drop-Ins
Universal components vs SwiftUI/Compose-specific surfaces.
Busque em todas as páginas da documentação
Universal components vs SwiftUI/Compose-specific surfaces.
@expo/ui permite que aplicativos Expo renderizem UI nativa - SwiftUI no iOS, Jetpack Compose no Android - a partir de componentes React. Use importações universais (Host, Column, Button) quando uma API deve funcionar em ambas as plataformas; opte por @expo/ui/swift-ui ou @expo/ui/jetpack-compose quando precisar de modificadores, materiais ou controles específicos da plataforma que não tenham um equivalente multiplataforma.
Cartão de receita de referência rápida - pronto para copiar e colar.
npx create-expo-app@latest MyExpoUIApp --template blank-typescript
cd MyExpoUIApp
npx expo install @expo/ui// screens/SettingsNativeScreen.tsx
import { Host, Column, Row, Text, Switch, Button, Spacer } from "@expo/ui";
export default function SettingsNativeScreen() {
return (
<Host style={{ flex: 1 }}>
<Column spacing={16} padding={16}>
<Text style={{ fontSize: 28, fontWeight: "700" }}>Notifications</Text>
<Row spacing={12} alignment="center">
<Column style={{ flex: 1 }}>
<Text style={{ fontSize: 17, fontWeight: "600" }}>Push alerts</Text>
<Text style={{ fontSize: 14, opacity: 0.7 }}>Order updates and promos</Text>
</Column>
<Switch defaultValue={true} label="Push alerts" />
</Row>
<Spacer />
<Button label="Save preferences" variant="borderedProminent" onPress={() => {}} />
</Column>
</Host>
);
}// Platform-specific enhancement (iOS only file pattern)
// components/GlassHeader.ios.tsx
import { Host, Text, VStack } from "@expo/ui/swift-ui";
import { background, glassEffect, padding } from "@expo/ui/swift-ui/modifiers";
export function GlassHeader({ title }: { title: string }) {
return (
<Host matchContents>
<VStack modifiers={[padding({ all: 16 }), glassEffect({ glass: { variant: "regular" } })]}>
<Text modifiers={[background("transparent")]}>{title}</Text>
</VStack>
</Host>
);
}// components/GlassHeader.tsx - Android fallback
import { Text, View } from "react-native";
export function GlassHeader({ title }: { title: string }) {
return (
<View style={{ padding: 16, backgroundColor: "#f1f5f9" }}>
<Text style={{ fontSize: 22, fontWeight: "700" }}>{title}</Text>
</View>
);
}Quando usar isso:
RNHostView.Tela de configurações híbrida: layout universal, RNHostView para uma ilha de gráfico React Native e cabeçalho de vidro apenas para iOS.
// screens/HybridDashboardScreen.tsx
import { Host, Column, Row, Text, Button, RNHostView } from "@expo/ui";
import { useColorScheme } from "react-native";
import { GlassHeader } from "../components/GlassHeader";
import { SpendingChart } from "../components/SpendingChart"; // standard RN component
export default function HybridDashboardScreen() {
const scheme = useColorScheme() ?? "light";
return (
<Host style={{ flex: 1, backgroundColor: scheme === "dark" ? "#0f172a" : "#f8fafc" }}>
<Column spacing={0} style={{ flex: 1 }}>
<GlassHeader title="Spending" />
<Column spacing={16} padding={16} style={{ flex: 1 }}>
<Row spacing={8} alignment="center">
<Text style={{ fontSize: 15, opacity: 0.75 }}>This month</Text>
<Text style={{ fontSize: 28, fontWeight: "700" }}>$1,284.00</Text>
</Row>
{/* RN island inside native layout */}
<Host style={{ flex: 1, minHeight: 220, borderRadius: 12, overflow: "hidden" }}>
<RNHostView style={{ flex: 1 }}>
<SpendingChart />
</RNHostView>
</Host>
<Button
label="View transactions"
variant="bordered"
onPress={() => {}}
accessibilityLabel="View transactions"
/>
</Column>
</Column>
</Host>
);
}// components/SpendingChart.tsx - ordinary React Native
import { View, Text, StyleSheet } from "react-native";
const BARS = [40, 65, 30, 80, 55];
export function SpendingChart() {
return (
<View style={styles.chart}>
{BARS.map((h, i) => (
<View key={i} style={[styles.bar, { height: h }]} />
))}
<Text style={styles.caption}>RN chart inside RNHostView</Text>
</View>
);
}
const styles = StyleSheet.create({
chart: { flex: 1, flexDirection: "row", alignItems: "flex-end", gap: 8, padding: 16, backgroundColor: "#fff" },
bar: { flex: 1, backgroundColor: "#2563eb", borderRadius: 4 },
caption: { position: "absolute", bottom: 8, left: 16, fontSize: 12, color: "#64748b" },
});O que isso demonstra:
Host é a raiz de toda árvore @expo/ui - layouts universais não funcionam sem ele.Column / Row usam layouts de pilha nativos com props spacing e alignment em vez de objetos de estilo flexbox.Button / Switch de @expo/ui são controles nativos, não wrappers Pressable.RNHostView incorpora componentes RN existentes em um chrome nativo - caminho de migração para sistemas de design híbridos..ios.tsx para APIs exclusivas de SwiftUI (glassEffect) com fallback RN no Android.@expo/ui faz a ponte entre props React e views SwiftUI / Compose via Expo Modules - a renderização ocorre na thread de UI nativa onde suportado.@expo/ui) escolhem a implementação da plataforma no momento da compilação - uma árvore de componentes, dois backends nativos.*.ios.tsx / *.android.tsx.RNHostView cria uma raiz RN aninhada dentro de um layout nativo - distinto de incorporação de tela inteira brownfield; veja RNHostView & Incorporação de UI Nativa.style limitados; superfícies SwiftUI preferem modificadores de @expo/ui/swift-ui/modifiers.| Importação | Renderiza | Usar para |
|---|---|---|
@expo/ui (Host, Column, Button) | SwiftUI + Compose | Chrome nativo multiplataforma |
@expo/ui/swift-ui | Apenas SwiftUI | Materiais, widgets, layouts de widget |
@expo/ui/jetpack-compose | Apenas Compose | Widgets Material do Android |
react-native (View, Pressable) | Layout RN | DS personalizado, listas, Skia, telas legadas |
import { Text, VStack } from "@expo/ui/swift-ui";
import { font, foregroundStyle, padding } from "@expo/ui/swift-ui/modifiers";
<Text
modifiers={[
font({ weight: "semibold", size: 17 }),
foregroundStyle("#111111"),
padding({ horizontal: 16 }),
]}
>
Hello
</Text>Modificadores não são style do RN - eles mapeiam para cadeias de modificadores SwiftUI. Extensões de widget usam o mesmo vocabulário - veja Extensões de App e Widgets.
| Camada | Ferramenta |
|---|---|
| Chrome nativo (barra de ferramentas, seletores) | @expo/ui |
| Listas e formulários densos | RN + Paper / Tamagui / NativeWind |
| Tokens de marca | Seu módulo de tokens - veja Noções Básicas de Sistemas de Design |
| Sabores de marca branca | Configuração de tema - veja Tematização e Sabores de Marca |
Falta do wrapper Host - Filhos do layout falham ao montar. Correção: Cada tela @expo/ui começa com <Host>.
Usando <View> dentro de arquivos de widget SwiftUI - Alvos de widget rejeitam primitivas RN. Correção: Apenas @expo/ui/swift-ui em pacotes de extensão.
Esperando pixels idênticos no iOS e Android - Componentes universais mapeiam para idiomas da plataforma; o espaçamento pode diferir. Correção: Projete para funções, não paridade de pixels.
RNHostView sem altura delimitada - Ilha de gráfico colapsa para zero. Correção: Defina minHeight ou flex: 1 no wrapper Host.
Importando modificadores SwiftUI no Android - Falha na compilação. Correção: Apenas arquivos específicos da plataforma ou componentes universais.
Substituindo o aplicativo inteiro por @expo/ui - Listas, navegação e bibliotecas RN de terceiros ainda precisam de layout RN. Correção: Use o chrome nativo seletivamente, não substituição completa.
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| @expo/ui universal | Switches nativos, botões, telas híbridas | Cada tela é uma lista complexa virtualizada |
| @expo/ui/swift-ui | Materiais iOS, widgets, Live Activities | Aplicativo apenas para Android |
| React Native Paper | Material Design em views RN | Você precisa de widgets Compose verdadeiros |
| Tamagui / NativeWind | DS de marca personalizado em toda a árvore RN | Efeitos de vidro e toggle nativos da plataforma |
| Views TurboModule personalizadas | Controle nativo sob medida não em @expo/ui | @expo/ui já envia o primitivo |
Sim para componentes universais e prototipagem RNHostView. Extensões de widget e alguns alvos apenas de plataforma exigem expo prebuild e builds de desenvolvimento.
O contêiner raiz que faz a ponte entre filhos React e hierarquias nativas SwiftUI/Compose. Envolva cada árvore de layout @expo/ui com <Host>.
Quando o chrome nativo (barra de ferramentas, controle segmentado) deve envolver telas RN existentes sem reescrevê-las. Veja RNHostView & Incorporação de UI Nativa.
Componentes universais aceitam props de estilo limitadas. Prefira props de layout (spacing, padding, alignment). Mantenha StyleSheet para filhos de RNHostView.
Modificadores compilam para cadeias SwiftUI (font, padding, glassEffect). Eles não se propagam como CSS. Use arquivos de plataforma quando os modificadores não tiverem um equivalente Android.
Paper renderiza Material em views RN. @expo/ui renderiza Compose/SwiftUI nativo. Você pode combiná-los - formulários Paper abaixo de um cabeçalho @expo/ui nativo.
Defina props label / accessibilityLabel onde exposto. Teste com VoiceOver e TalkBack - controles nativos se comportam de forma diferente de Pressable. Veja Noções Básicas de Acessibilidade.
Versões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026