フレームワーク(オープンソースソフトウェア)。Expo で美しく、ネイティブアプリのような見た目の画面を構築できます。Apple の Human Interface Guidelines(Appleが定めた設計指針)に準拠したスタイル、意味を持つ色、ネイティブコントロール、SF シンボル(Apple の統一アイコン集)、メディア、アニメーション、ビジュアルエフェクト、グラデーション、データ保存、レスポンシブレイアウト(画面サイズに応じた自動調整)に対応しています。ルーティング(ページ間の移動先指定)とナビゲーション(画面遷移)については、expo-router スキルを使用してください。
Framework (OSS). Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, animations, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill.
ルート、リンク、スタック、タブ、モーダル、シート、ヘッダーについては expo-router スキルを使用してください。
UIコンポーネントを選ぶ前に、まず
expo-uiを確認してください。@expo/uiはネイティブな代替コンポーネント(BottomSheet、Button、Picker、Slider、Menu、Section、Switch、SegmentedControl など)を提供し、iOS では実際の SwiftUI として、Android では Jetpack Compose(Android の UI構築フレームワーク)として描画されます。SDK 56 以降の Expo Go で利用でき、カスタムビルドは不要です。expo-uiスキルを読み込んで、React Native 組み込みやコミュニティライブラリに頼る前に適切なコンポーネントを見つけてください。このスキル(expo-native-ui)は Expo Router のナビゲーション、レイアウト、スタイリング、アニメーションなど、周辺の構造をカバーしています。
必要に応じてこれらの資料を参照してください:
references/
animations.md Reanimated: 入場・退場・レイアウト・スクロール連動・ジェスチャーアニメーション
controls.md iOS ネイティブ: Switch、Slider、SegmentedControl、DateTimePicker、Picker
gradients.md CSS グラデーション(experimental_backgroundImage / New Arch のみ)
icons.md SF Symbols(expo-image で sf: ソース指定)、名前、アニメーション、太さ
media.md カメラ、音声、ビデオ、ファイル保存
storage.md SQLite、AsyncStorage、SecureStore
visual-effects.md ブラー(expo-blur)とガラス効果(expo-glass-effect)
webgpu-three.md 3D グラフィックス、ゲーム、WebGPU と Three.js を使った GPU ビジュアライゼーション
重要: カスタムビルドを作成する前に、必ず Expo Go で試してください。
ほとんどの Expo アプリはカスタムネイティブコードなしに Expo Go で動作します。npx expo run:ios または npx expo run:android を実行する前に:
npx expo start を実行し、Expo Go で QR コードをスキャンしてください次を使用する場合のみ npx expo run:ios/android または eas build が必要です:
modules/ にあるカスタムネイティブコード)@bacons/apple-targets でウィジェット、アプリクリップ、拡張機能など)app.json では表現できないカスタムネイティブ設定Expo Go はすぐに使えるたくさんの機能をサポートしています:
expo-* パッケージ(カメラ、位置情報、通知など)迷ったら、まず Expo Go で試してください。 カスタムビルドは複雑性が増し、反復が遅くなり、Xcode/Android Studio の設定が必要です。
comment-card.tsx@expo/ui(expo-ui スキルを参照)を使用してください。ネイティブ SwiftUI/Compose として描画され、SDK 56+ の Expo Go で動作します。グループ化・設定画面のような行(短い、固定長)には @expo/ui の List + ListItem を使用してください。大きさや長さが不確定なスクローリストリスト(フィード、検索結果、カタログ)には FlatList または FlashList を使用してください。@expo/ui の List は仮想化(仮想スクロール)に対応していませんexpo-av ではなく expo-audio を使用してくださいexpo-av ではなく expo-video を使用してくださいexpo-symbols や @expo/vector-icons ではなく、expo-image に source="sf:name" を指定して使用してくださいreact-native-safe-area-context を使用してくださいPlatform.OS ではなく process.env.EXPO_OS を使用してくださいReact.useContext ではなく React.use を使用してくださいimg ではなく expo-image の Image コンポーネントを使用してくださいexpo-glass-effect を使用してくださいPlatformColor ではなく expo-router の Color を使用してください@react-navigation/* から直接インポートしないでください。代わりに expo-router/react-navigation を使用してください(@react-navigation/native、/core、/elements、/routers をカバーしています)<SafeAreaView> の代わりに <ScrollView contentInsetAdjustmentBehavior="automatic" /> を使用してスマートなセーフエリア制御を行ってくださいcontentInsetAdjustmentBehavior="automatic" は FlatList と SectionList にも適用してくださいDimensions.get() ではなく useWindowDimensions を常に優先してください<Switch /> や @react-native-community/datetimepicker など、ハプティクス機能がビルトインされたビューを使用してくださいcontentInsetAdjustmentBehavior="automatic" を設定した ScrollView である必要がありますScrollView を追加する場合、ほぼ常にルートコンポーネント内の最初のコンポーネントにしてください<Text selectable /> プロップを使用してくださいimg や div などの組み込み要素を使用しないでくださいApple ヒューマンインターフェースガイドラインに従ってください。
contentInsetAdjustmentBehavior="automatic" のいずれかで考慮してください{ borderCurve: 'continuous' } を使用してくださいcontentContainerStyle のパディングとギャップを使用してください(クリッピングを減らします)expo-router の Color API を使用してネイティブセマンティックカラーを使用してください。これは PlatformColor に対するタイプセーフなラッパーで、iOS UIKit カラーを Color.ios.* で、Android Material 3 カラーを Color.android.material.*(静的)または Color.android.dynamic.*(Android 12+ ではユーザーの壁紙に適応)で公開しています。これらはデバイス上で解決され、ライト/ダークモードとアクセシビリティ設定に自動適応するため、別のライト/ダーク十六進数テーブルや colors.web.ts ファイルを保守する必要がなくなります。
Color はプラットフォーム固有なので、各値を Platform.select でラップし、Web 向けの十六進数フォールバックを提供してください。パレットを theme/colors.ts に集約し、すべての場所から colors をインポートしてください:
// theme/colors.ts
import { Platform } from "react-native";
import { Color } from "expo-router";
export const colors = {
label: Platform.select({
ios: Color.ios.label,
android: Color.android.dynamic.onSurface,
default: "#000000",
})!,
secondaryLabel: Platform.select({
ios: Color.ios.secondaryLabel,
android: Color.android.dynamic.onSurfaceVariant,
default: "#3c3c43",
})!,
separator: Platform.select({
ios: Color.ios.separator,
android: Color.android.dynamic.outlineVariant,
default: "#c6c6c8",
})!,
systemBackground: Platform.select({
ios: Color.ios.systemBackground,
android: Color.android.dynamic.surface,
default: "#ffffff",
})!,
systemBlue: Platform.select({
ios: Color.ios.systemBlue,
android: Color.android.dynamic.primary,
default: "#007aff",
})!,
};
import { colors } from "@/theme/colors";
<View style={{ backgroundColor: colors.systemBackground }}>
<Text style={{ color: colors.label }}>Title</Text>
</View>;
useColorScheme() を呼び出して、テーマが切り替わったときに再描画されるようにしてください(React Compiler がコンポーネントをメモ化する場合に必須です)Color / PlatformColor の値を Reanimated スタイルに渡さないでください。そこでは静的色を使用してください(references/animations.md を参照)Platform.select({...})! は string | OpaqueColorValue を返します。ほとんどの React Native スタイルプロップは ColorValue(string | OpaqueColorValue)を受け入れるため、これは正常に機能します。ただし、一部のサードパーティプロップは string のみを受け入れます(例: expo-image の tintColor)。必要に応じてキャストしてください: colors.label as string<Text/> 要素には常に selectable プロップを追加してください{ fontVariant: 'tabular-nums' } を使用して配置を調整してくださいCSS の boxShadow スタイルプロップを使用してください。レガシーな React Native のシャドウまたはエレベーションスタイルを絶対に使用しないでください。
<View style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }} />
インセットシャドウがサポートされています。
このスキルにエラー、誤解を招く情報、または古い情報が見つかった場合、
For routes, links, stacks, tabs, modals, sheets, and headers, use the expo-router skill.
Before picking any UI component, check
expo-uifirst.@expo/uiprovides native equivalents — BottomSheet, Button, Picker, Slider, Menu, Section, Switch, SegmentedControl, and more — rendered as real SwiftUI on iOS and Jetpack Compose on Android, available in Expo Go on SDK 56+ with no custom build. Load theexpo-uiskill to find the right component before falling back to React Native built-ins or community libraries. This skill (expo-native-ui) covers the surrounding structure: Expo Router navigation, layout, styling, and animations.
Consult these resources as needed:
references/
animations.md Reanimated: entering, exiting, layout, scroll-driven, gestures
controls.md Native iOS: Switch, Slider, SegmentedControl, DateTimePicker, Picker
gradients.md CSS gradients via experimental_backgroundImage (New Arch only)
icons.md SF Symbols via expo-image (sf: source), names, animations, weights
media.md Camera, audio, video, and file saving
storage.md SQLite, AsyncStorage, SecureStore
visual-effects.md Blur (expo-blur) and liquid glass (expo-glass-effect)
webgpu-three.md 3D graphics, games, GPU visualizations with WebGPU and Three.js
CRITICAL: Always try Expo Go first before creating custom builds.
Most Expo apps work in Expo Go without any custom native code. Before running npx expo run:ios or npx expo run:android:
npx expo start and scan the QR code with Expo GoYou need npx expo run:ios/android or eas build ONLY when using:
modules/)@bacons/apple-targets)app.jsonExpo Go supports a huge range of features out of the box:
expo-* packages (camera, location, notifications, etc.)If you're unsure, try Expo Go first. Creating custom builds adds complexity, slower iteration, and requires Xcode/Android Studio setup.
comment-card.tsx@expo/ui (see expo-ui skill) before reaching for a React Native built-in or community library — it renders native SwiftUI/Compose and works in Expo Go on SDK 56+. For grouped/settings-style rows (short, fixed-length), use @expo/ui's List + ListItem. For large or unknown-length scrolling lists (feeds, search results, catalogs), use FlatList or FlashList — @expo/ui's List is not virtualized.expo-audio not expo-avexpo-video not expo-avexpo-image with source="sf:name" for SF Symbols, not expo-symbols or @expo/vector-iconsreact-native-safe-area-context not react-native SafeAreaViewprocess.env.EXPO_OS not Platform.OSReact.use not React.useContextexpo-image Image component instead of intrinsic element imgexpo-glass-effect for liquid glass backdropsColor from expo-router for native semantic colors, not raw PlatformColor (type-safe, auto-adapts to light/dark)@react-navigation/* directly — use expo-router/react-navigation instead (covers @react-navigation/native, /core, /elements, /routers)<ScrollView contentInsetAdjustmentBehavior="automatic" /> instead of <SafeAreaView> for smarter safe area insetscontentInsetAdjustmentBehavior="automatic" should be applied to FlatList and SectionList as welluseWindowDimensions over Dimensions.get() to measure screen size<Switch /> from React Native and @react-native-community/datetimepickercontentInsetAdjustmentBehavior="automatic" setScrollView to the page it should almost always be the first component inside the route component<Text selectable /> prop on text containing data that could be copiedFollow Apple Human Interface Guidelines.
contentInsetAdjustmentBehavior="automatic"{ borderCurve: 'continuous' } for rounded corners unless creating a capsule shapecontentContainerStyle padding and gap instead of padding on the ScrollView itself (reduces clipping)Use the Color API from expo-router for native semantic colors. It is a type-safe wrapper over PlatformColor that exposes iOS UIKit colors through Color.ios.* and Android Material 3 colors through Color.android.material.* (static) or Color.android.dynamic.* (adapts to the user's wallpaper on Android 12+). These resolve on-device and automatically adapt to light/dark mode and accessibility settings, so you no longer maintain separate light/dark hex tables or a colors.web.ts file.
Color is platform-specific, so wrap each value in Platform.select with a default hex fallback for web. Centralize the palette in theme/colors.ts and import colors everywhere:
// theme/colors.ts
import { Platform } from "react-native";
import { Color } from "expo-router";
export const colors = {
label: Platform.select({
ios: Color.ios.label,
android: Color.android.dynamic.onSurface,
default: "#000000",
})!,
secondaryLabel: Platform.select({
ios: Color.ios.secondaryLabel,
android: Color.android.dynamic.onSurfaceVariant,
default: "#3c3c43",
})!,
separator: Platform.select({
ios: Color.ios.separator,
android: Color.android.dynamic.outlineVariant,
default: "#c6c6c8",
})!,
systemBackground: Platform.select({
ios: Color.ios.systemBackground,
android: Color.android.dynamic.surface,
default: "#ffffff",
})!,
systemBlue: Platform.select({
ios: Color.ios.systemBlue,
android: Color.android.dynamic.primary,
default: "#007aff",
})!,
};
import { colors } from "@/theme/colors";
<View style={{ backgroundColor: colors.systemBackground }}>
<Text style={{ color: colors.label }}>Title</Text>
</View>;
useColorScheme() inside any component that renders them so it re-renders when the theme flips (required when React Compiler memoizes the component).Color / PlatformColor values into Reanimated styles — use static colors there (see references/animations.md).Platform.select({...})! returns string | OpaqueColorValue. Most React Native style props accept ColorValue (string | OpaqueColorValue) so this works fine. But some third-party props only accept string (e.g. tintColor on expo-image). Cast when needed: colors.label as string.selectable prop to every <Text/> element displaying important data or error messages{ fontVariant: 'tabular-nums' } for alignmentUse CSS boxShadow style prop. NEVER use legacy React Native shadow or elevation styles.
<View style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }} />
'inset' shadows are supported.
If you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:
npx --yes submit-expo-feedback@latest --category skills --subject "expo-native-ui" "<actionable feedback>"
Only submit when you have something specific and actionable to report. Include as much relevant context as possible. If an AI agent repeatedly failed or the user had to take over an Expo task, load the expo-skill-feedback skill and follow its eval-candidate flow instead of reusing the command above.
原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。