diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js
index 620dd8fdad98e8..dbf500a25925fd 100644
--- a/Libraries/Components/View/ReactNativeStyleAttributes.js
+++ b/Libraries/Components/View/ReactNativeStyleAttributes.js
@@ -134,6 +134,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
textShadowOffset: true,
textShadowRadius: true,
textTransform: true,
+ userSelect: true,
writingDirection: true,
/**
diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js
index a78e58061d8be5..ee11fab8aa5d26 100644
--- a/Libraries/StyleSheet/StyleSheetTypes.js
+++ b/Libraries/StyleSheet/StyleSheetTypes.js
@@ -632,6 +632,7 @@ export type ____TextStyle_InternalCore = $ReadOnly<{
textDecorationStyle?: 'solid' | 'double' | 'dotted' | 'dashed',
textDecorationColor?: ____ColorValue_Internal,
textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase',
+ userSelect?: 'auto' | 'text' | 'none' | 'contain' | 'all',
writingDirection?: 'auto' | 'ltr' | 'rtl',
}>;
diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js
index 57b6a2ea82ca28..2337efee07d3c1 100644
--- a/Libraries/Text/Text.js
+++ b/Libraries/Text/Text.js
@@ -20,6 +20,7 @@ import {NativeText, NativeVirtualText} from './TextNativeComponent';
import {type TextProps} from './TextProps';
import * as React from 'react';
import {useContext, useMemo, useState} from 'react';
+import flattenStyle from '../StyleSheet/flattenStyle';
/**
* Text is the fundamental component for displaying text.
@@ -152,7 +153,13 @@ const Text: React.AbstractComponent<
? null
: processColor(restProps.selectionColor);
- let style = restProps.style;
+ let style = flattenStyle(restProps.style);
+
+ let _selectable = restProps.selectable;
+ if (style?.userSelect != null) {
+ _selectable = userSelectToSelectableMap[style.userSelect];
+ }
+
if (__DEV__) {
if (PressabilityDebug.isEnabled() && onPress != null) {
style = StyleSheet.compose(restProps.style, {
@@ -182,6 +189,7 @@ const Text: React.AbstractComponent<
{...eventHandlersForText}
isHighlighted={isHighlighted}
isPressable={isPressable}
+ selectable={_selectable}
numberOfLines={numberOfLines}
selectionColor={selectionColor}
style={style}
@@ -193,6 +201,7 @@ const Text: React.AbstractComponent<
{...restProps}
{...eventHandlersForText}
disabled={_disabled}
+ selectable={_selectable}
accessible={_accessible}
accessibilityState={_accessibilityState}
allowFontScaling={allowFontScaling !== false}
@@ -222,4 +231,12 @@ function useLazyInitialization(newValue: boolean): boolean {
return oldValue;
}
+const userSelectToSelectableMap = {
+ auto: true,
+ text: true,
+ none: false,
+ contain: true,
+ all: true,
+};
+
module.exports = Text;
diff --git a/packages/rn-tester/js/examples/Text/TextExample.android.js b/packages/rn-tester/js/examples/Text/TextExample.android.js
index 8980335aba1361..45826991731aca 100644
--- a/packages/rn-tester/js/examples/Text/TextExample.android.js
+++ b/packages/rn-tester/js/examples/Text/TextExample.android.js
@@ -982,4 +982,14 @@ exports.examples = [
return ;
},
},
+ {
+ title: 'Selectable Text',
+ render: function (): React.Node {
+ return (
+
+ Text element is selectable
+
+ );
+ },
+ },
];
diff --git a/packages/rn-tester/js/examples/Text/TextExample.ios.js b/packages/rn-tester/js/examples/Text/TextExample.ios.js
index 96c19353c25c5c..d24c35ca1638eb 100644
--- a/packages/rn-tester/js/examples/Text/TextExample.ios.js
+++ b/packages/rn-tester/js/examples/Text/TextExample.ios.js
@@ -1227,4 +1227,14 @@ exports.examples = [
);
},
},
+ {
+ title: 'Selectable Text',
+ render: function (): React.Node {
+ return (
+
+ Text element is selectable
+
+ );
+ },
+ },
];