High-performance, fully customizable text selection component for React Native using Skia rendering
npm install react-native-advanced-selectable-text

High-performance, fully customizable text selection component for React Native using Skia rendering. Achieve "ChatGPT-style" text selection with custom cursors, handles, and floating menus.


- 🎨 Skia-powered rendering - Smooth 60fps selection animations
- 📱 Cross-platform - iOS, Android, and Web (Expo compatible)
- 🔗 Multiple Instances - Coordinated selection across many components (perfect for chat feeds)
- ✨ Customizable - Selection colors, cursor styles, handle appearance
- 🎯 Precise selection - Draggable handles with swap support
- 💬 Floating menu - Animated action menu with custom options
- ⚡ Reanimated worklets - UI thread gesture handling
- 🛡️ Strongly Typed - Full TypeScript support, zero any
``bashnpm
npm install react-native-advanced-selectable-text
$3
This package requires the following peer dependencies:
`bash
npm
npm install @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-workletsExpo
npx expo install @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-worklets
`Basic Usage
Wrap your application (or specific screen) with
SelectionProvider to enable coordinated selection handling.`tsx
import {
SelectableText,
SelectionProvider,
useSelection,
} from "react-native-advanced-selectable-text";
import { GestureHandlerRootView } from "react-native-gesture-handler";function Example() {
const { selection, clearSelection } = useSelection();
return (
clearSelection()}>
text="Long-press me for selection!"
menuOptions={[
{ label: "Copy", onPress: (text) => console.log("Copy:", text) },
]}
/>
);
}
export default function App() {
return (
);
}
`Advanced: Coordinated chat list
When using
SelectionProvider, multiple SelectableText instances will automatically coordinate. Starting a selection in one message will automatically clear the selection in others.`tsx
{messages.map((msg) => (
key={msg.id}
text={msg.content}
menuOptions={globalMenuOptions}
/>
))}
`Props
| Prop | Type | Default | Description |
| ------------------- | ---------------------------------------- | ------------------------- | ---------------------------------------------- |
|
text | string | required | The text content to display |
| menuOptions | MenuOption[] | required | Array of menu options |
| fontSize | number | 16 | Font size in points |
| fontFamily | string | System font | Font family name |
| textColor | string | #000000 | Text color |
| selectionColor | string | rgba(59, 130, 246, 0.3) | Selection highlight color |
| cursorColor | string | #3b82f6 | Cursor and handle color |
| width | number | Container width | Fixed width for text layout |
| style | ViewStyle | - | Container style |
| selection | Selection \| null | - | Overrides internal selection (controlled mode) |
| onSelectionChange | (selection: Selection \| null) => void | - | Selection change callback |Hooks
$3
Used inside a
SelectionProvider to access or manipulate the active selection.`ts
const {
selection, // Current active selection object
clearSelection, // Function to clear all selections in the provider
setSelection, // Manually set the selection
onSelectionChange, // Standard handler for SelectableText
} = useSelection();
`Architecture
- Skia Paragraph API: Used for advanced text layout and measuring glyph positions.
- Selection Coordination: Controlled via React Context and internal unique instance IDs.
- Gesture Performance: All gestures run on the UI thread using Reanimated worklets for lag-free handle dragging.
Development
`bash
Install dependencies
bun installBuild the library
bun run buildRun example app
cd apps/example
bun run ios # or ‘android’
``MIT