{"id":"e7593fa3-d8d0-421e-8c2c-1f9e3163c293","shortId":"YqXWUV","kind":"skill","title":"cometchat-native-placement","tagline":"Where to put chat in a React Native app — Stack screen, BottomTab, Modal, BottomSheet, Embedded. Maps each to CometChat component composition with ASCII layout references.","description":"## Purpose\n\nTeaches Claude the five canonical placement patterns for putting chat inside a React Native app. Each pattern specifies:\n\n1. Which CometChat components to compose\n2. How to wire the placement into `@react-navigation/*` (or Expo Router)\n3. Platform gotchas (safe-area, keyboard avoiding, gesture handling)\n4. When to choose this placement over the alternatives\n\nGround truth: `docs/ui-kit/react-native/react-native-conversation.mdx`, `react-native-one-to-one-chat.mdx`, `react-native-tab-based-chat.mdx`, their `expo-*.mdx` equivalents, and the `examples/SampleApp/` + `examples/SampleAppExpo/` sample apps.\n\n**Read `cometchat-native-core` and `cometchat-native-components` before this skill** — the provider wrapper chain and component catalog are prerequisites.\n\n---\n\n## \"What are you building?\" — placement recommendation\n\nUse this table to pick a placement. If the user says \"add chat to my app\" without specifying where, ask them what they're building.\n\n| User intent | Recommended placement | Experience |\n|---|---|---|\n| Messaging app (WhatsApp / Telegram / Signal style) | **Conversations stack** — list → tap → full-page messages screen | Two-pane-equivalent on mobile |\n| SaaS / marketplace / e-commerce with chat as a feature | **Stack screen** — dedicated `/chat` or `/messages` route | Full-page chat inside the app |\n| Support app or focused 1-to-1 | **Stack screen (single thread)** — no conversation list, go straight into one chat | Single thread |\n| Full messaging hub with calls / users / groups | **Bottom tabs** — Chats / Users / Groups / Calls tabs + stack screen for message view | Tab-based messenger |\n| Occasional chat overlay from a non-chat screen | **Modal** — present from anywhere, dismiss to return | Modal |\n| Inline comments / contextual chat | **BottomSheet** — swipe up from a screen section | Sheet |\n| Chat embedded inside an existing screen (e.g. a support tab next to product details) | **Embedded** — CometChat components inside a parent layout | Embedded |\n\n---\n\n## Visual reference — five RN placement patterns\n\n### 1. Stack screen (full page)\n\n```\n┌───────────────────────────────────┐\n│ ← Hiking Group               ⋮    │  ← CometChatMessageHeader\n├───────────────────────────────────┤\n│                                   │\n│                ╭──────────╮       │\n│                │ Message  │       │\n│                ╰──────────╯       │  ← CometChatMessageList\n│                                   │\n│  ╭──────────╮                     │\n│  │ Reply    │                     │\n│  ╰──────────╯                     │\n│                                   │\n├───────────────────────────────────┤\n│ +  Type a message...          ▶   │  ← CometChatMessageComposer\n└───────────────────────────────────┘\n```\n\n### 2. Bottom tab\n\n```\n┌───────────────────────────────────┐\n│ ← Hiking Group               ⋮    │  ← header\n├───────────────────────────────────┤\n│                                   │\n│           (messages)              │\n│                                   │\n├───────────────────────────────────┤\n│  Chats  Users  Groups  Calls      │  ← bottom tab bar\n└───────────────────────────────────┘\n```\n\n### 3. Modal (slide-up over current screen)\n\n```\n              ┌─────────────────┐\n              │ ═══ Chat  ✕     │  ← drag handle + close\n              ├─────────────────┤\n              │                 │\n              │   (messages)    │\n              │                 │\n              ├─────────────────┤\n              │ Type message ▶  │\n              └─────────────────┘\n  (parent screen dimmed behind)\n```\n\n### 4. BottomSheet (swipe-up partial)\n\n```\nparent screen visible at top ─────\n              ┌─────────────────┐\n              │  ═══ (handle)   │\n              │ Hiking Group    │\n              ├─────────────────┤\n              │   (messages)    │\n              ├─────────────────┤\n              │ Type message ▶  │\n              └─────────────────┘\n```\n\n### 5. Embedded (inside an existing screen)\n\n```\n┌───────────────────────────────────┐\n│ Product details                   │\n│ [product image + specs]           │\n├───────────────────────────────────┤\n│ Contact seller                    │  ← section heading\n│ ┌────────────────────────────┐    │\n│ │ (CometChatMessageHeader)    │    │\n│ │ (CometChatMessageList)      │    │  ← embedded chat\n│ │ (CometChatMessageComposer)  │    │\n│ └────────────────────────────┘    │\n└───────────────────────────────────┘\n```\n\n---\n\n## 1. Stack screen\n\nThe most common pattern — chat lives in its own screen, pushed via `@react-navigation/native-stack`.\n\n### Pattern A — Conversations list → Messages\n\nTwo screens: list + messages.\n\n```tsx\n// ConversationsScreen.tsx\nimport { CometChatConversations, CometChatUiKitConstants } from \"@cometchat/chat-uikit-react-native\";\nimport type { NativeStackNavigationProp } from \"@react-navigation/native-stack\";\n\nexport function ConversationsScreen({ navigation }: { navigation: NativeStackNavigationProp<any> }) {\n  return (\n    <CometChatConversations\n      onItemPress={(conversation) => {\n        const type = conversation.getConversationType();\n        if (type === CometChatUiKitConstants.ConversationTypeConstants.user) {\n          navigation.navigate(\"Messages\", { user: conversation.getConversationWith() });\n        } else {\n          navigation.navigate(\"Messages\", { group: conversation.getConversationWith() });\n        }\n      }}\n    />\n  );\n}\n```\n\n```tsx\n// MessagesScreen.tsx\nimport { View } from \"react-native\";\nimport {\n  CometChatMessageHeader,\n  CometChatMessageList,\n  CometChatMessageComposer,\n} from \"@cometchat/chat-uikit-react-native\";\n\nexport function MessagesScreen({ route, navigation }: any) {\n  const { user, group } = route.params ?? {};\n  return (\n    <View style={{ flex: 1 }}>\n      <CometChatMessageHeader user={user} group={group} onBack={() => navigation.goBack()} showBackButton />\n      <CometChatMessageList user={user} group={group} hideReplyInThreadOption />\n      <CometChatMessageComposer user={user} group={group} />\n    </View>\n  );\n}\n```\n\n```tsx\n// AppNavigator.tsx\nimport { createNativeStackNavigator } from \"@react-navigation/native-stack\";\nconst Stack = createNativeStackNavigator();\n\n<Stack.Navigator screenOptions={{ headerShown: false }}>\n  <Stack.Screen name=\"Conversations\" component={ConversationsScreen} />\n  <Stack.Screen name=\"Messages\" component={MessagesScreen} />\n</Stack.Navigator>\n```\n\n### Pattern B — Single thread (no conversation list)\n\nFor support chat, marketplace \"Contact seller\", or any focused 1-to-1 where the target user/group is known in advance.\n\n```tsx\nexport function SupportChatScreen() {\n  const [agent, setAgent] = useState<CometChat.User | null>(null);\n  const [loading, setLoading] = useState(true);\n\n  useEffect(() => {\n    CometChat.getUser(\"support-agent-uid\")\n      .then((user) => {\n        setAgent(user);\n        setLoading(false);\n      })\n      .catch(() => setLoading(false));\n  }, []);\n\n  if (loading) return <ActivityIndicator style={{ flex: 1 }} />;\n  if (!agent) return <Text style={{ padding: 16 }}>Support unavailable. Try again shortly.</Text>;\n\n  return (\n    <View style={{ flex: 1 }}>\n      <CometChatMessageHeader user={agent} />\n      <CometChatMessageList user={agent} hideReplyInThreadOption />\n      <CometChatMessageComposer user={agent} />\n    </View>\n  );\n}\n```\n\n### Navigation wiring notes\n\n- The screen is wrapped in a `<View style={{ flex: 1 }}>` so the composer sits at the bottom and the list fills the middle.\n- `CometChatMessageHeader`'s `onBack` should call `navigation.goBack()`. Set `showBackButton` explicitly so the header knows to render it.\n- **Keyboard avoiding**: when the composer is visible, RN needs `KeyboardAvoidingView` on iOS or `android:windowSoftInputMode=\"adjustResize\"` on Android. The framework patterns (`cometchat-native-expo-patterns`, `cometchat-native-bare-patterns`) cover the platform-specific wiring.\n\n---\n\n## 2. Bottom tab\n\nFor full-featured messengers with distinct entry points per content type.\n\n```tsx\n// TabsNavigator.tsx\nimport { createBottomTabNavigator } from \"@react-navigation/bottom-tabs\";\nimport { createNativeStackNavigator } from \"@react-navigation/native-stack\";\n\nconst Tab = createBottomTabNavigator();\nconst Stack = createNativeStackNavigator();\n\nfunction MainTabs() {\n  return (\n    <Tab.Navigator screenOptions={{ headerShown: false }}>\n      <Tab.Screen name=\"Chats\" component={ConversationsScreen} />\n      <Tab.Screen name=\"Users\" component={UsersScreen} />\n      <Tab.Screen name=\"Groups\" component={GroupsScreen} />\n      <Tab.Screen name=\"Calls\" component={CallLogsScreen} />\n    </Tab.Navigator>\n  );\n}\n\nexport function AppNavigator() {\n  return (\n    <Stack.Navigator screenOptions={{ headerShown: false }}>\n      <Stack.Screen name=\"Main\" component={MainTabs} />\n      <Stack.Screen name=\"Messages\" component={MessagesScreen} />\n    </Stack.Navigator>\n  );\n}\n```\n\nEach tab screen pushes to a shared `Messages` stack screen with the selected entity:\n\n```tsx\nexport function UsersScreen({ navigation }: any) {\n  return (\n    <CometChatUsers onItemPress={(user) => navigation.navigate(\"Messages\", { user })} />\n  );\n}\nexport function GroupsScreen({ navigation }: any) {\n  return (\n    <CometChatGroups onItemPress={(group) => navigation.navigate(\"Messages\", { group })} />\n  );\n}\nexport function CallLogsScreen() {\n  return <CometChatCallLogs />;\n}\n```\n\n### Wiring notes\n\n- Tabs use `@react-navigation/bottom-tabs`. The `Messages` screen is OUTSIDE the tab navigator (at the stack level) so it presents full-screen without the tab bar.\n- For the **Calls** tab, `CometChatCallLogs` only works when `@cometchat/calls-sdk-react-native` is installed. Omit the Calls tab if the project doesn't use calling.\n\n---\n\n## 3. Modal\n\nFor occasional chat that doesn't belong in the primary navigation. Two approaches — native RN `<Modal>` or react-navigation's `presentation: \"modal\"`.\n\n### Pattern A — React Navigation modal (recommended)\n\nCleaner — the modal is a regular stack screen with a modal presentation option.\n\n```tsx\n<Stack.Navigator screenOptions={{ headerShown: false }}>\n  <Stack.Screen name=\"Home\" component={HomeScreen} />\n  <Stack.Screen\n    name=\"ChatModal\"\n    component={ChatModalScreen}\n    options={{ presentation: \"modal\" }}\n  />\n</Stack.Navigator>\n```\n\n```tsx\nfunction ChatModalScreen({ navigation }: any) {\n  const [agent, setAgent] = useState<CometChat.User | null>(null);\n  useEffect(() => { CometChat.getUser(\"support-agent\").then(setAgent); }, []);\n  if (!agent) return null;\n  return (\n    <View style={{ flex: 1 }}>\n      <CometChatMessageHeader user={agent} onBack={() => navigation.goBack()} showBackButton />\n      <CometChatMessageList user={agent} hideReplyInThreadOption />\n      <CometChatMessageComposer user={agent} />\n    </View>\n  );\n}\n\n// Trigger from anywhere:\n<Button title=\"Contact support\" onPress={() => navigation.navigate(\"ChatModal\")} />\n```\n\niOS gets the native modal slide-up. Android shows a fade-in full-screen by default — if you need a swipe-to-dismiss feel, use the BottomSheet pattern instead.\n\n### Pattern B — RN `<Modal>` component\n\nFor lightweight one-off modals that don't need a separate route.\n\n```tsx\nimport { Modal, Pressable, View } from \"react-native\";\n\nconst [visible, setVisible] = useState(false);\n\n<Modal visible={visible} animationType=\"slide\" onRequestClose={() => setVisible(false)}>\n  <SafeAreaView style={{ flex: 1 }}>\n    <View style={{ flex: 1 }}>\n      <CometChatMessageHeader user={agent} onBack={() => setVisible(false)} showBackButton />\n      <CometChatMessageList user={agent} hideReplyInThreadOption />\n      <CometChatMessageComposer user={agent} />\n    </View>\n  </SafeAreaView>\n</Modal>\n```\n\nWorks fine but bypasses navigation state — deep links and back-button handling need extra work.\n\n---\n\n## 4. BottomSheet\n\nNative-feel swipe-up chat overlaid on a parent screen. Two library options; pick one based on the project's existing navigation:\n\n| Library | When to use |\n|---|---|\n| `@gorhom/bottom-sheet` | Most flexible + most common. Good for partial-height sheets with snap points. |\n| `@cometchat/chat-uikit-react-native`'s `CometChatBottomSheet` | Lightweight. Good if the project doesn't already depend on `@gorhom/bottom-sheet`. |\n\n### Pattern A — @gorhom/bottom-sheet\n\n```tsx\nimport BottomSheet, { BottomSheetView } from \"@gorhom/bottom-sheet\";\nimport { useRef, useMemo } from \"react\";\n\nfunction ProductScreen({ product }: any) {\n  const sheetRef = useRef<BottomSheet>(null);\n  const snapPoints = useMemo(() => [\"25%\", \"90%\"], []);\n  const [agent, setAgent] = useState<CometChat.User | null>(null);\n\n  useEffect(() => {\n    CometChat.getUser(product.sellerUid).then(setAgent);\n  }, [product.sellerUid]);\n\n  return (\n    <View style={{ flex: 1 }}>\n      <ProductDetails product={product} />\n      <Button title=\"Contact seller\" onPress={() => sheetRef.current?.expand()} />\n\n      <BottomSheet ref={sheetRef} snapPoints={snapPoints} index={-1} enablePanDownToClose>\n        <BottomSheetView style={{ flex: 1 }}>\n          {agent && (\n            <>\n              <CometChatMessageHeader user={agent} />\n              <CometChatMessageList user={agent} hideReplyInThreadOption />\n              <CometChatMessageComposer user={agent} />\n            </>\n          )}\n        </BottomSheetView>\n      </BottomSheet>\n    </View>\n  );\n}\n```\n\n### Pattern B — CometChatBottomSheet\n\n```tsx\nimport { CometChatBottomSheet } from \"@cometchat/chat-uikit-react-native\";\n\nconst sheetRef = useRef<any>(null);\n\n<CometChatBottomSheet ref={sheetRef}>\n  <View style={{ flex: 1, height: \"100%\" }}>\n    <CometChatMessageHeader user={agent} />\n    <CometChatMessageList user={agent} hideReplyInThreadOption />\n    <CometChatMessageComposer user={agent} />\n  </View>\n</CometChatBottomSheet>\n\n<Button title=\"Chat\" onPress={() => sheetRef.current?.show()} />\n```\n\n### BottomSheet gotchas\n\n- **Snap points must be memoized**: Always wrap `snapPoints` in `useMemo(() => [...], [])` (see Pattern A above). An inline array creates a new reference on every parent render, which forces `@gorhom/bottom-sheet` to re-measure layout and tears the open/close gesture animation. The example above does this correctly — do NOT \"simplify\" by inlining the array.\n- **Keyboard behavior**: `@gorhom/bottom-sheet` has `keyboardBehavior` + `keyboardBlurBehavior` props. Without them the composer gets covered by the keyboard on iOS. Use `keyboardBehavior=\"interactive\"` + `keyboardBlurBehavior=\"restore\"`.\n- **Gesture handler wrap**: BottomSheet requires `<GestureHandlerRootView style={{ flex: 1 }}>` at the root (already required by the UI Kit — see `cometchat-native-core` § 3).\n- **Height**: Pass `flex: 1` + `height: \"100%\"` on the inner View so the message list expands to fill the sheet.\n\n---\n\n## 5. Embedded\n\nChat inside an existing screen, not its own route.\n\n```tsx\nexport function ProductDetailScreen({ product }: any) {\n  const [agent, setAgent] = useState<CometChat.User | null>(null);\n  useEffect(() => { CometChat.getUser(product.sellerUid).then(setAgent); }, [product.sellerUid]);\n\n  return (\n    <ScrollView style={{ flex: 1 }} keyboardShouldPersistTaps=\"handled\">\n      <ProductImages images={product.images} />\n      <ProductSpecs product={product} />\n\n      <View style={{ marginTop: 24 }}>\n        <Text style={{ fontSize: 18, fontWeight: \"600\", padding: 16 }}>Chat with seller</Text>\n        <View style={{ height: 480 }}>\n          {agent && (\n            <>\n              <CometChatMessageHeader user={agent} />\n              <CometChatMessageList user={agent} hideReplyInThreadOption />\n              <CometChatMessageComposer user={agent} />\n            </>\n          )}\n        </View>\n      </View>\n    </ScrollView>\n  );\n}\n```\n\n### Embedded gotchas\n\n- **Fixed height required.** CometChat components fill 100% of their parent. If you put them inside a `ScrollView` without a bounded height, the list collapses to zero height. Wrap in a `<View style={{ height: NNN }}>` or flex container with an explicit height.\n- **Scroll conflict.** If the parent is a `ScrollView`, the message list's internal scroll competes with the parent's scroll. Consider the single-thread-as-stack-screen pattern instead if the chat is a primary UX.\n- **Composer focus.** When the user taps the composer, the keyboard rises and can push the embedded chat off-screen on iOS. `keyboardShouldPersistTaps=\"handled\"` on the parent ScrollView + `KeyboardAvoidingView` at the root help.\n\nUsually the embedded pattern is the wrong default — prefer a Modal or BottomSheet trigger from a button on the screen, which gives users a dedicated surface for chatting.\n\n---\n\n## Hard rules\n\nThese apply to ALL placement patterns. Violating any of them causes integration bugs or destroys the existing navigation.\n\n1. **NEVER modify the project's existing navigator without reading it first.** Understand what's there before adding screens or tabs. Don't replace a user's navigation structure unless they explicitly chose \"demo mode.\"\n\n2. **ALWAYS use a separate screen / stack entry for chat**, not inline replacement of an existing screen. The one exception is embedded placement (§ 5) where chat is explicitly part of a bigger screen.\n\n3. **The four-wrapper chain is required at the app root**, not per-screen (see `cometchat-native-core` § 3). Re-wrapping per screen causes duplicate init + login, dropped WebSockets, and a 2–3-second flicker on first mount.\n\n4. **`import \"react-native-gesture-handler\"`** must be at the very top of `index.js` (or Expo entry). Missing this import silently disables swipe gestures in the composer, bottom sheet, and attachment drawer.\n\n5. **Every `<CometChatMessageList>` MUST include `hideReplyInThreadOption`** unless the integration also wires a full thread panel (`CometChatThreadHeader` + scoped list + scoped composer with `parentMessageId`). Drawer / modal / bottom sheet / embedded / stack-screen placements without a thread panel **must include the flag** — otherwise \"Reply in Thread\" shows in the message menu and silently does nothing.\n\n6. **Resolve user / group before rendering.** The component props `user` and `group` expect `CometChat.User` and `CometChat.Group` instances — not bare UID strings. Fetch via `CometChat.getUser(uid)` / `CometChat.getGroup(guid)` in a `useEffect` and gate the render on the resolved object.\n\n7. **Pass either `user` or `group`, never both.** Passing both causes runtime errors. Branch in render based on which one is set.\n\n8. **Every CometChat container must have explicit flex height.** Components fill 100% of parent. If parent has no bounded height (`flex: 1`, `height: N`, or inside a flex layout with `flex: N`), components collapse to zero height and render empty. This is THE most common \"why is my chat blank\" bug.\n\n9. **For modals and bottom sheets, set `keyboardShouldPersistTaps=\"handled\"`** on any ScrollView / FlatList parent and configure keyboard behavior explicitly. Otherwise the composer gets hidden by the keyboard on iOS.\n\n10. **Never animate a CometChat-containing container with `transform`** (including Tailwind's `translate-x-*` / `translate-y-*` / `scale-*` / `rotate-*` utilities if using NativeWind). `transform` creates a new containing block for `position: \"absolute\"` descendants, which reparents CometChat's absolute-positioned overlays (emoji picker, action sheet, reactions popover) and makes them misalign. In RN this is less common than web (RN has no `position: fixed`) but the same rule applies to any `position: absolute` pickers. Animate `right` / `left` / `top` / `bottom` offsets instead.\n\n---\n\n## Skill routing reference\n\n| Skill | When to route |\n|---|---|\n| `cometchat-native-core` | Always first — init, login, provider wrapper chain |\n| `cometchat-native-components` | For component prop details — always |\n| `cometchat-native-placement` | This skill — picking + wiring a placement |\n| `cometchat-native-expo-patterns` | Expo-specific integration (app.json, permissions, Expo Router) |\n| `cometchat-native-bare-patterns` | Bare RN (pod install, native modules, privacy manifest) |\n| `cometchat-native-theming` | Customize colors / typography / dark mode |\n| `cometchat-native-features` | Calls, extensions, AI — the \"add a feature\" flow |\n| `cometchat-native-customization` | Custom slot views, text formatters, events |\n| `cometchat-native-production` | Server-side auth tokens |\n| `cometchat-native-troubleshooting` | Blank chat / gestures not working / keyboard covering composer / pod install fails |","tags":["cometchat","native","placement","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-native-placement","topic-agent-skills","topic-ai-agent","topic-chat","topic-claude-code","topic-cometchat","topic-cursor","topic-messaging","topic-nextjs","topic-react","topic-react-native","topic-ui-kit"],"categories":["cometchat-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cometchat/cometchat-skills/cometchat-native-placement","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cometchat/cometchat-skills","source_repo":"https://github.com/cometchat/cometchat-skills","install_from":"skills.sh"}},"qualityScore":"0.463","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 27 github stars · SKILL.md body (20,480 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:04:54.649Z","embedding":null,"createdAt":"2026-05-07T13:05:14.977Z","updatedAt":"2026-05-18T19:04:54.649Z","lastSeenAt":"2026-05-18T19:04:54.649Z","tsv":"'-1':211,551,1222 '/bottom-tabs':727,836 '/chat':194 '/messages':196 '/native-stack':409,433,515,734 '1':49,209,306,391,487,549,597,614,637,969,1068,1072,1205,1227,1257,1361,1380,1430,1630,1905 '10':1964 '100':1259,1382,1477,1895 '16':604,1450 '18':1446 '2':55,321,704,1665,1733 '24':1442 '25':1186 '3':68,335,881,1376,1698,1719,1734 '4':78,354,1103,1740 '480':1457 '5':371,1396,1688,1773 '6':1824 '600':1448 '7':1862 '8':1884 '9':1935 '90':1187 'absolut':1997,2004,2038 'absolute-posit':2003 'action':2009 'activityind':594 'ad':1647 'add':141,2127 'adjustres':682 'advanc':559 'agent':565,580,599,617,620,624,948,958,962,972,978,982,1075,1082,1086,1189,1228,1231,1234,1238,1262,1265,1269,1414,1458,1461,1464,1468 'ai':2125 'alreadi':1157,1365 'also':1781 'altern':86 'alway':1283,1666,2058,2073 'android':680,684,1001 'anim':1316,1966,2040 'animationtyp':1060 'anywher':261,985 'app':13,45,101,145,161,204,206,1708 'app.json':2093 'appli':1613,2034 'appnavig':770 'appnavigator.tsx':508 'approach':895 'area':73 'array':1294,1329 'ascii':27 'ask':149 'attach':1771 'auth':2148 'avoid':75,668 'b':534,1027,1240 'back':1097 'back-button':1096 'bar':334,858 'bare':696,1842,2100,2102 'base':247,1122,1878 'behavior':1331,1952 'behind':353 'belong':889 'bigger':1696 'blank':1933,2154 'block':1994 'bottom':233,322,332,644,705,1768,1796,1939,2044 'bottomsheet':18,270,355,1023,1104,1166,1216,1276,1356,1594 'bottomsheetview':1167,1224 'bottomtab':16 'bound':1490,1902 'branch':1875 'bug':1624,1934 'build':127,154 'button':986,1098,1209,1270,1598 'bypass':1090 'call':230,238,331,655,765,861,872,880,2123 'calllogsscreen':767,827 'canon':35 'catalog':121 'catch':588 'caus':1622,1725,1872 'chain':118,1703,2064 'chat':8,40,142,187,201,223,235,250,256,269,278,328,343,389,398,542,750,885,1111,1272,1398,1451,1544,1565,1609,1674,1690,1932,2155 'chatmod':936,992 'chatmodalscreen':938,944 'choos':81 'chose':1662 'claud':32 'cleaner':911 'close':346 'collaps':1494,1917 'color':2115 'cometchat':2,23,51,104,109,293,689,694,1373,1474,1716,1886,1969,2001,2055,2066,2075,2085,2098,2111,2120,2132,2142,2151 'cometchat-contain':1968 'cometchat-native-bare-pattern':693,2097 'cometchat-native-compon':108,2065 'cometchat-native-cor':103,1372,1715,2054 'cometchat-native-custom':2131 'cometchat-native-expo-pattern':688,2084 'cometchat-native-featur':2119 'cometchat-native-plac':1,2074 'cometchat-native-product':2141 'cometchat-native-them':2110 'cometchat-native-troubleshoot':2150 'cometchat.getgroup':1849 'cometchat.getuser':577,955,1196,1421,1847 'cometchat.group':1839 'cometchat.user':568,951,1192,1417,1837 'cometchat/calls-sdk-react-native':867 'cometchat/chat-uikit-react-native':425,472,1147,1246 'cometchatbottomsheet':1149,1241,1244,1251 'cometchatcalllog':863 'cometchatconvers':422,441 'cometchatgroup':819 'cometchatmessagecompos':320,390,470,502,622,980,1084,1236,1267,1466 'cometchatmessagehead':313,386,468,488,615,651,970,1073,1229,1260,1459 'cometchatmessagelist':315,387,469,496,618,976,1080,1232,1263,1462 'cometchatthreadhead':1787 'cometchatuikitconst':423 'cometchatuikitconstants.conversationtypeconstants.user':449 'cometchatus':807 'comment':267 'commerc':185 'common':396,1137,1928,2022 'compet':1526 'compon':24,52,111,120,294,526,531,751,756,761,766,779,784,932,937,1029,1475,1831,1893,1916,2068,2070 'compos':54,640,671,1340,1549,1556,1767,1791,1956,2161 'composit':25 'configur':1950 'conflict':1513 'consid':1532 'const':444,479,516,564,571,735,738,947,1052,1179,1183,1188,1247,1413 'contact':382,544,988,1211 'contain':1507,1887,1970,1971,1993 'content':717 'contextu':268 'convers':166,217,412,443,525,538 'conversation.getconversationtype':446 'conversation.getconversationwith':453,458 'conversationsscreen':436,527,752 'conversationsscreen.tsx':420 'core':106,1375,1718,2057 'correct':1322 'cover':698,1342,2160 'creat':1295,1990 'createbottomtabnavig':722,737 'createnativestacknavig':510,518,729,740 'current':341 'custom':2114,2134,2135 'dark':2117 'dedic':193,1606 'deep':1093 'default':1011,1589 'demo':1663 'depend':1158 'descend':1998 'destroy':1626 'detail':291,378,2072 'dim':352 'disabl':1762 'dismiss':262,1019 'distinct':713 'docs/ui-kit/react-native/react-native-conversation.mdx':89 'doesn':877,887,1155 'drag':344 'drawer':1772,1794 'drop':1729 'duplic':1726 'e':184 'e-commerc':183 'e.g':284 'either':1864 'els':454 'embed':19,279,292,299,372,388,1397,1469,1564,1584,1686,1798 'emoji':2007 'empti':1923 'enablepandowntoclos':1223 'entiti':799 'entri':714,1672,1757 'equival':95,178 'error':1874 'event':2140 'everi':1300,1774,1885 'exampl':1318 'examples/sampleapp':98 'examples/sampleappexpo':99 'except':1684 'exist':282,375,1127,1401,1628,1636,1680 'expand':1215,1391 'expect':1836 'experi':159 'explicit':659,1510,1661,1692,1890,1953 'expo':66,93,691,1756,2087,2090,2095 'expo-specif':2089 'export':434,473,561,768,801,813,825,1408 'extens':2124 'extra':1101 'fade':1005 'fade-in':1004 'fail':2164 'fals':522,587,590,747,775,928,1056,1064,1078 'featur':190,710,2122,2129 'feel':1020,1107 'fetch':1845 'fill':648,1393,1476,1894 'fine':1088 'first':1641,1738,2059 'five':34,302 'fix':1471,2029 'flag':1810 'flatlist':1947 'flex':486,596,613,636,968,1067,1071,1204,1226,1256,1360,1379,1429,1506,1891,1904,1911,1914 'flexibl':1135 'flicker':1736 'flow':2130 'focus':208,548,1550 'fontsiz':1445 'fontweight':1447 'forc':1304 'formatt':2139 'four':1701 'four-wrapp':1700 'framework':686 'full':171,199,226,309,709,853,1008,1784 'full-featur':708 'full-pag':170,198 'full-screen':852,1007 'function':435,474,562,741,769,802,814,826,943,1175,1409 'gate':1855 'gestur':76,1315,1353,1745,1764,2156 'gesturehandlerrootview':1358 'get':994,1341,1957 'give':1603 'go':219 'good':1138,1151 'gorhom/bottom-sheet':1133,1160,1163,1169,1305,1332 'gotcha':70,1277,1470 'ground':87 'group':232,237,312,325,330,367,457,481,491,492,499,500,505,506,760,821,824,1827,1835,1867 'groupsscreen':762,815 'guid':1850 'handl':77,345,365,1099,1432,1572,1943 'handler':1354,1746 'hard':1610 'head':385 'header':326,662 'headershown':521,746,774,927 'height':1142,1258,1377,1381,1456,1472,1491,1497,1503,1511,1892,1903,1906,1920 'help':1581 'hidden':1958 'hidereplyinthreadopt':501,621,979,1083,1235,1266,1465,1777 'hike':311,324,366 'home':931 'homescreen':933 'hub':228 'imag':380,1434 'import':421,426,461,467,509,721,728,1044,1165,1170,1243,1741,1760 'includ':1776,1808,1974 'index':1221 'index.js':1754 'init':1727,2060 'inlin':266,1293,1327,1676 'inner':1385 'insid':41,202,280,295,373,1399,1485,1909 'instal':869,2105,2163 'instanc':1840 'instead':1025,1541,2046 'integr':1623,1780,2092 'intent':156 'interact':1350 'intern':1524 'io':678,993,1347,1570,1963 'keyboard':74,667,1330,1345,1558,1951,1961,2159 'keyboardavoidingview':676,1577 'keyboardbehavior':1334,1349 'keyboardblurbehavior':1335,1351 'keyboardshouldpersisttap':1431,1571,1942 'kit':1370 'know':663 'known':557 'layout':28,298,1310,1912 'left':2042 'less':2021 'level':848 'librari':1118,1129 'lightweight':1031,1150 'link':1094 'list':168,218,413,417,539,647,1390,1493,1522,1789 'live':399 'load':572,592 'login':1728,2061 'main':778 'maintab':742,780 'make':2014 'manifest':2109 'map':20 'margintop':1441 'marketplac':182,543 'mdx':94 'measur':1309 'memoiz':1282 'menu':1819 'messag':160,173,227,243,314,319,327,347,349,368,370,414,418,451,456,530,783,793,811,823,838,1389,1521,1818 'messagesscreen':475,532,785 'messagesscreen.tsx':460 'messeng':248,711 'middl':650 'misalign':2016 'miss':1758 'mobil':180 'modal':17,258,265,336,882,904,909,913,921,941,997,1035,1045,1057,1592,1795,1937 'mode':1664,2118 'modifi':1632 'modul':2107 'mount':1739 'must':1280,1747,1775,1807,1888 'n':1907,1915 'name':524,529,749,754,759,764,777,782,930,935 'nativ':3,12,44,105,110,466,690,695,896,996,1051,1106,1374,1717,1744,2056,2067,2076,2086,2099,2106,2112,2121,2133,2143,2152 'native-feel':1105 'nativestacknavigationprop':428,439 'nativewind':1988 'navig':64,408,432,437,438,477,514,625,726,733,804,816,835,844,893,901,908,945,1091,1128,1629,1637,1657 'navigation.goback':494,656,974 'navigation.navigate':450,455,810,822,991 'need':675,1014,1039,1100 'never':1631,1868,1965 'new':1297,1992 'next':288 'nnn':1504 'non':255 'non-chat':254 'note':627,830 'noth':1823 'null':569,570,952,953,964,1182,1193,1194,1250,1418,1419 'object':1861 'occasion':249,884 'off-screen':1566 'offset':2045 'omit':870 'onback':493,653,973,1076 'one':222,1033,1121,1683,1881 'one-off':1032 'onitempress':442,808,820 'onpress':990,1213,1273 'onrequestclos':1062 'open/close':1314 'option':923,939,1119 'otherwis':1811,1954 'outsid':841 'overlaid':1112 'overlay':251,2006 'pad':603,1449 'page':172,200,310 'pane':177 'panel':1786,1806 'parent':297,350,360,1115,1301,1480,1516,1529,1575,1897,1899,1948 'parentmessageid':1793 'part':1693 'partial':359,1141 'partial-height':1140 'pass':1378,1863,1870 'pattern':37,47,305,397,410,533,687,692,697,905,1024,1026,1161,1239,1289,1540,1585,1617,2088,2101 'per':716,1712,1723 'per-screen':1711 'permiss':2094 'pick':134,1120,2080 'picker':2008,2039 'placement':4,36,60,83,128,136,158,304,1616,1687,1802,2077,2083 'platform':69,701 'platform-specif':700 'pod':2104,2162 'point':715,1146,1279 'popov':2012 'posit':1996,2005,2028,2037 'prefer':1590 'prerequisit':123 'present':259,851,903,922,940 'pressabl':1046 'primari':892,1547 'privaci':2108 'product':290,377,379,1177,1207,1208,1411,1437,1438,2144 'product.images':1435 'product.selleruid':1197,1200,1422,1425 'productdetail':1206 'productdetailscreen':1410 'productimag':1433 'productscreen':1176 'productspec':1436 'project':876,1125,1154,1634 'prop':1336,1832,2071 'provid':116,2062 'purpos':30 'push':404,789,1562 'put':7,39,1483 're':153,1308,1721 're-measur':1307 're-wrap':1720 'react':11,43,63,407,431,465,513,725,732,834,900,907,1050,1174,1743 'react-nat':464,1049 'react-native-gesture-handl':1742 'react-native-one-to-one-chat.mdx':90 'react-native-tab-based-chat.mdx':91 'react-navig':62,406,430,512,724,731,833,899 'reaction':2011 'read':102,1639 'recommend':129,157,910 'ref':1217,1252 'refer':29,301,1298,2049 'regular':916 'render':665,1302,1829,1857,1877,1922 'repar':2000 'replac':1653,1677 'repli':316,1812 'requir':1357,1366,1473,1705 'resolv':1825,1860 'restor':1352 'return':264,440,483,593,600,610,743,771,806,818,828,963,965,1201,1426 'right':2041 'rise':1559 'rn':303,674,897,1028,2018,2025,2103 'root':1364,1580,1709 'rotat':1984 'rout':197,476,1042,1406,2048,2053 'route.params':482 'router':67,2096 'rule':1611,2033 'runtim':1873 'saa':181 'safe':72 'safe-area':71 'safeareaview':1065 'sampl':100 'say':140 'scale':1983 'scope':1788,1790 'screen':15,174,192,213,241,257,275,283,308,342,351,361,376,393,403,416,629,788,795,839,854,918,1009,1116,1402,1539,1568,1601,1648,1670,1681,1697,1713,1724,1801 'screenopt':520,745,773,926 'scroll':1512,1525,1531 'scrollview':1427,1487,1519,1576,1946 'second':1735 'section':276,384 'see':1288,1371,1714 'select':798 'seller':383,545,1212,1453 'separ':1041,1669 'server':2146 'server-sid':2145 'set':657,1883,1941 'setag':566,584,949,960,1190,1199,1415,1424 'setload':573,586,589 'setvis':1054,1063,1077 'share':792 'sheet':277,1143,1395,1769,1797,1940,2010 'sheetref':1180,1218,1248,1253 'sheetref.current':1214,1274 'short':609 'show':1002,1275,1815 'showbackbutton':495,658,975,1079 'side':2147 'signal':164 'silent':1761,1821 'simplifi':1325 'singl':214,224,535,1535 'single-thread-as-stack-screen':1534 'sit':641 'skill':114,2047,2050,2079 'skill-cometchat-native-placement' 'slide':338,999,1061 'slide-up':337,998 'slot':2136 'snap':1145,1278 'snappoint':1184,1219,1220,1285 'source-cometchat' 'spec':381 'specif':702,2091 'specifi':48,147 'stack':14,167,191,212,240,307,392,517,739,794,847,917,1538,1671,1800 'stack-screen':1799 'stack.navigator':519,772,925 'stack.screen':523,528,776,781,929,934 'state':1092 'straight':220 'string':1844 'structur':1658 'style':165,485,595,602,612,635,967,1066,1070,1203,1225,1255,1359,1428,1440,1444,1455,1502 'support':205,286,541,579,605,957,989 'support-ag':956 'support-agent-uid':578 'supportchatscreen':563 'surfac':1607 'swipe':271,357,1017,1109,1763 'swipe-to-dismiss':1016 'swipe-up':356,1108 'tab':234,239,246,287,323,333,706,736,787,831,843,857,862,873,1650 'tab-bas':245 'tab.navigator':744 'tab.screen':748,753,758,763 'tabl':132 'tabsnavigator.tsx':720 'tailwind':1975 'tap':169,1554 'target':554 'teach':31 'tear':1312 'telegram':163 'text':601,1443,2138 'theme':2113 'thread':215,225,536,1536,1785,1805,1814 'titl':987,1210,1271 'token':2149 'top':364,1752,2043 'topic-agent-skills' 'topic-ai-agent' 'topic-chat' 'topic-claude-code' 'topic-cometchat' 'topic-cursor' 'topic-messaging' 'topic-nextjs' 'topic-react' 'topic-react-native' 'topic-ui-kit' 'transform':1973,1989 'translat':1978,1981 'translate-i':1980 'translate-x':1977 'tri':607 'trigger':983,1595 'troubleshoot':2153 'true':575 'truth':88 'tsx':419,459,507,560,719,800,924,942,1043,1164,1242,1407 'two':176,415,894,1117 'two-pane-equival':175 'type':317,348,369,427,445,448,718 'typographi':2116 'ui':1369 'uid':581,1843,1848 'unavail':606 'understand':1642 'unless':1659,1778 'use':130,832,879,1021,1132,1348,1667,1987 'useeffect':576,954,1195,1420,1853 'usememo':1172,1185,1287 'user':139,155,231,236,329,452,480,489,490,497,498,503,504,583,585,616,619,623,755,809,812,971,977,981,1074,1081,1085,1230,1233,1237,1261,1264,1268,1460,1463,1467,1553,1604,1655,1826,1833,1865 'user/group':555 'useref':1171,1181,1249 'usersscreen':757,803 'usest':567,574,950,1055,1191,1416 'usual':1582 'util':1985 'ux':1548 'via':405,1846 'view':244,462,484,611,634,966,1047,1069,1202,1254,1386,1439,1454,1501,2137 'violat':1618 'visibl':362,673,1053,1058,1059 'visual':300 'web':2024 'websocket':1730 'whatsapp':162 'windowsoftinputmod':681 'wire':58,626,703,829,1782,2081 'without':146,855,1337,1488,1638,1803 'work':865,1087,1102,2158 'wrap':631,1284,1355,1498,1722 'wrapper':117,1702,2063 'wrong':1588 'x':1979 'y':1982 'zero':1496,1919","prices":[{"id":"7aaaea3a-ccd7-4947-8889-4c3bc19e5801","listingId":"e7593fa3-d8d0-421e-8c2c-1f9e3163c293","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cometchat","category":"cometchat-skills","install_from":"skills.sh"},"createdAt":"2026-05-07T13:05:14.977Z"}],"sources":[{"listingId":"e7593fa3-d8d0-421e-8c2c-1f9e3163c293","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-native-placement","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-native-placement","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:14.977Z","lastSeenAt":"2026-05-18T19:04:54.649Z"}],"details":{"listingId":"e7593fa3-d8d0-421e-8c2c-1f9e3163c293","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-native-placement","github":{"repo":"cometchat/cometchat-skills","stars":27,"topics":["agent-skills","ai-agent","chat","claude-code","cometchat","cursor","messaging","nextjs","react","react-native","ui-kit"],"license":null,"html_url":"https://github.com/cometchat/cometchat-skills","pushed_at":"2026-05-18T05:04:24Z","description":"Add CometChat chat to any React, Next.js, React Native, Angular, Android, iOS, or Flutter project through your AI coding agent. Works with Claude Code, Cursor, Codex, VS Code Copilot, Windsurf, Cline, Kiro, and 50+ more agents.","skill_md_sha":"dc45959c733281c4185769296f88d81a960faab8","skill_md_path":"skills/cometchat-native-placement/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-native-placement"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-native-placement","license":"MIT","description":"Where to put chat in a React Native app — Stack screen, BottomTab, Modal, BottomSheet, Embedded. Maps each to CometChat component composition with ASCII layout references.","compatibility":"Node.js >=18; React Native >=0.70; @cometchat/chat-uikit-react-native ^5"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-native-placement"},"updatedAt":"2026-05-18T19:04:54.649Z"}}