### Introduction `<Text selectable>` works very differently on iOS and Android. On Android a long-press lets the user drag selection handles and copy any substring. On iOS it only shows a single-action "Copy" tooltip that copies the **entire** block. No partial highlight is possible. This has been reported repeatedly since RN 0.39 (issues [#13938](https://github.com/facebook/react-native/issues/13938), [#35997](https://github.com/facebook/react-native/issues/35997)) but is still not implemented today. Digging through the native code (and Apple docs) shows why: React Native renders iOS `<Text>` with **`UILabel`**, and `UILabel` has no built-in text-selection APIs. `UITextView` does, but isn’t used here([stackoverflow.com](https://stackoverflow.com/questions/45541208/i-want-native-ios-copy-and-paste-ui-on-uilabel)). Because many apps (chat, note-taking, markdown viewers) need full selection, developers resort to work-arounds such as an invisible `<TextInput editable={false}>` or the community module [**react-native-uitextview**](https://github.com/bluesky-social/react-native-uitextview) ([stackoverflow.com](https://stackoverflow.com/questions/33728469/how-to-touch-and-hold-to-select-text-in-react-native)). Both options carry heavy trade-offs. ### Details **Current behaviour** ```jsx <Text selectable> Long-press me on iOS -> you can only "Copy" everything. </Text> ``` * Android – expected: drag handles, contextual menu, partial copy. * iOS – actual: "Copy" tooltip, whole paragraph copied. **Why we shouldn't use UILabel** Apple’s docs and multiple blog posts confirm `UILabel` cannot expose selection. Making it copyable requires custom `UIMenuController` and still yields block-level copy only([stackoverflow.com](https://stackoverflow.com/questions/45541208/i-want-native-ios-copy-and-paste-ui-on-uilabel), [medium.com](https://medium.com/kinandcartacreated/making-uilabel-accessible-5f3d5c342df4)). **Work-arounds and limitations** | Work-around | Pros | Cons | | -------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `TextInput` (`editable={false}`) | Full selection | Breaks scrolling inside parent `ScrollView`, shows keyboard on some OS builds, different styling and accessibility issues | | `react-native-uitextview` | Full selection, translation, share sheet | Component is a **LeafYogaNode**. Any wrapper `<View>` / `<ScrollView>` inside it gets a `0×0` frame unless you write custom native recursion. Integrating into rich-text layouts (markdown, chat bubbles) becomes complex | **Typical real-world use case** A markdown viewer renders heterogeneous nodes: ```jsx <MarkdownViewer content={` 1. First item 2. Second item Inline \\(a^2+b^2=c^2\\). \`\`\`js console.log('code'); \`\`\` `} /> ``` During parsing the tree may look like: ``` <View> <Text>“1. First…”</Text> <View class="bulletList">…</View> <ScrollView horizontal> …LaTeX SVG… </ScrollView> <CodeBlock>…</CodeBlock> <Text>“More text”</Text> </View> ``` Both `<View>` and `<ScrollView>` nodes need Yoga layout (padding, scroll) and must not break the contiguous selection across the full content. **Proposed direction: container + leaf** A platform component pair: ```jsx <SelectableContainer> <Text selectable>Inline prose …</Text> <MyBulletList/> {/* ordinary View – keeps Yoga layout */} <CodeBlock>…</CodeBlock> <Text selectable>More prose …</Text> </SelectableContainer> ``` * **`<Text selectable>`** – leaf, `MeasurableYogaNode + LeafYogaNode`, backed by `UITextView` fragments. * **`<SelectableContainer>`** – normal Yoga view. At draw time it walks its subtree, flattens all descendant `SelectableText` into **one** native `UITextView`, and overlays it. Non-text children keep their own layout boxes, so code blocks, LaTeX scroll views, images, etc., still render and scroll correctly. (To be confirmed if it's faisable, not sure about that 😅, but I hope so 🤞) Main features we want: * Full-range selection across multiple paragraphs, list items, etc. * No layout regressions for block. ### Discussion points 1. **API** – Would core maintainers consider acceptable adding something like a `SelectableContainer` ? 2. **Alternative** – Instead of new components, expose a `selectionMode="range"` prop on existing `<Text>` that internally switches from `UILabel` to `UITextView` ? 3. **Performance & memory** – Any concerns with large strings in a single `UITextView`? 5. **Use-case coverage** – Does the container/leaf split satisfy other complex scenarios ? 6. **Am I missing something** – Maybe we have other trade-off that are blocking doing this ? Looking forward to feedback and guidance, or if a different approach would be preferred.