Expo UI (@expo/ui)
@expo/ui renderiza UI nativa real a partir do React: SwiftUI no iOS, Jetpack Compose no Android. Também inclui substituições drop-in para migrar de bibliotecas de UI da comunidade RN.
Estas instruções acompanham o Expo SDK mais recente. A camada universal requer SDK 56+ e funciona no Expo Go — sem necessidade de build personalizado. As substituições drop-in e as camadas específicas de plataforma também existem no SDK 55. Para detalhes de componentes em um SDK específico, consulte a documentação do Expo UI para essa versão.
Instalação
npx expo install @expo/ui
Toda árvore @expo/ui — universal ou específica de plataforma — deve ser envolvida em Host.
Use @expo/ui por padrão — não recorra primeiro a alternativas do RN
Antes de usar Reanimated, @gorhom/bottom-sheet, Switch/Picker nativos do React Native ou qualquer biblioteca de UI da comunidade para os itens abaixo, use @expo/ui. Recorra aos componentes nativos do RN apenas quando @expo/ui não tiver o componente.
| Necessidade | Use |
|---|---|
| Folha deslizante / bottom sheet | BottomSheet do @expo/ui — não Reanimated ou @gorhom/bottom-sheet |
| Linhas de lista nativa agrupadas (estilo configurações/formulário) | List + ListItem do @expo/ui — não FlatList (veja nota abaixo) |
| Alternância | Switch do @expo/ui |
| Controle deslizante | Slider do @expo/ui |
| Seletor de data/hora | @expo/ui/community/datetimepicker |
| Menu | Menu do @expo/ui |
| Seção de formulário com rótulo | FieldGroup do @expo/ui |
| Seção recolhível | Collapsible do @expo/ui |
ListNÃO é uma lista de rolagem virtualizada. Ela renderiza linhas de tabela agrupadas nativas — o visual de uma tela de Configurações do iOS ou de uma seção de formulário, com indicadores de divulgação e estilo de linha nativo. CadaListItemé um nó nativo na thread JS; as linhas não são recicladas. Para qualquer lista com dados grandes ou de comprimento desconhecido (feeds, resultados de pesquisa, catálogos), useFlatListouFlashList.Listé a escolha certa para grupos curtos e de tamanho fixo: uma tela de configurações, as linhas de um painel de detalhes, um menu fixo.
Exemplo de BottomSheet (use para detalhes de pinos no mapa, folhas de ação, painéis de detalhes — não Reanimated):
import { Host, BottomSheet, Column, Text } from '@expo/ui';
import { useState } from 'react';
export default function MapScreen() {
const [isOpen, setIsOpen] = useState(false);
return (
<View style={{ flex: 1 }}>
<MapView onMarkerPress={() => setIsOpen(true)} />
<Host>
<BottomSheet
isPresented={isOpen}
onDismiss={() => setIsOpen(false)}
snapPoints={['half', 'full']}
>
<Column>
<Text>Café name</Text>
<Text>Address</Text>
</Column>
</BottomSheet>
</Host>
</View>
);
}
BottomSheet usa isPresented/onDismiss — não isOpened, isOpen, onIsOpenedChange ou onChange (esses são props de @gorhom/bottom-sheet e não farão nada silenciosamente). snapPoints aceita 'half', 'full', { fraction: 0.5 } ou { height: 400 } e é opcional (redimensiona automaticamente para o conteúdo quando omitido).
Escolhendo uma abordagem
Percorra esta lista e pare na primeira camada que atender à necessidade:
-
Componentes universais — comece aqui. Importe da raiz
@expo/ui. Uma única árvore de componentes é executada sem modificações no iOS, Android e web a partir de uma única fonte (Compose no Android, SwiftUI no iOS,react-native-web/react-domna web). Sem divisões de arquivos por plataforma. →./references/universal.md -
Específicos de plataforma (SwiftUI / Jetpack Compose). Importe de
@expo/ui/swift-uiou@expo/ui/jetpack-compose. Use apenas quando a camada universal não tiver um componente ou modificador necessário, ou quando você precisar de comportamento ou otimização específicos da plataforma. Desvantagem: você escreve duas árvores e as divide em arquivos.ios.tsx/.android.tsx(ou ramifica emPlatform.OS) — mais código para manter.@expo/ui/swift-uié apenas iOS.@expo/ui/jetpack-composeé apenas Android. Importar qualquer um deles em um arquivo executado na outra plataforma causará um erro em tempo de execução com "Unable to get view config". Isole árvores específicas de plataforma em arquivos.ios.tsx/.android.tsxcolocados emcomponents/(nunca dentro deapp/— o Expo Router não suporta extensões de plataforma para arquivos de rota), ou proteja comPlatform.OSem um arquivo de rota normal.Hostdeve ser sempre importado de@expo/ui(pacote universal raiz), não dos subpacotes específicos de plataforma. →./references/swift-ui.mde./references/jetpack-compose.md
Já está usando uma biblioteca de UI da comunidade RN? @expo/ui também fornece substituições drop-in — trocas compatíveis com a API para bibliotecas populares (@gorhom/bottom-sheet, @react-native-community/datetimepicker e mais), importadas de @expo/ui/community/<nome>. Este é um caminho lateral de migração para substituir uma dependência existente, não uma etapa na decisão universal vs. plataforma acima. → ./references/drop-in-replacements.md
Referências
Consulte estes recursos conforme necessário:
references/
universal.md Componentes universais @expo/ui e quando usá-los (SDK 56+)
drop-in-replacements.md Substituições compatíveis com a API para bibliotecas de UI da comunidade RN
swift-ui.md UI específica do iOS: componentes, modificadores, RNHostView, useNativeState de @expo/ui/swift-ui
jetpack-compose.md UI específica do Android: componentes, modificadores, ressalva LazyColumn, ícones, useNativeState de @expo/ui/jetpack-compose
Enviando Feedback
Se você encontrar erros, informações enganosas ou desatualizadas neste skill, reporte para que o Expo possa melhorar:
npx --yes submit-expo-feedback@latest --category skills --subject "expo-ui" "<feedback acionável>"
Envie apenas quando tiver algo específico e acionável para relatar. Inclua o máximo de contexto relevante possível. Se um agente de IA falhou repetidamente ou o usuário teve que assumir uma tarefa do Expo, carregue o skill expo-skill-feedback e siga seu fluxo de avaliação de candidato em vez de reutilizar o comando acima.