skip to Main Content

I’m currently using for letting user to select and copy contents from a Text block

<Text selectable={true}>some text</Text>

The problem is that when using scrolling or tabbing to switch different Text block, or screen, the "Selection Action" is popped up too quickly.
The behavior is like whenever a user is scrolling or swiping, the screen does not get scrolled or swiped, instead some text are selected and the Copy/Paste action buttons are popped up.

I’m seeking that if the Text component has a delay option for triggering selectable, no luck, so my idea is to use the onLongPress function to manually trigger the selectable popup? is that possible?

In addition:
Making an variable to control the selectable from onLongPress event does not work, because it only sets the Text component selectable to true at long press, it does not instantly show the text selecting UI and Copy/Paste action buttons
User must release the press and repress it again to bring up the selection tools popup

3

Answers


  1. You can implement a workaround using the onLongPress event and a state variable to control the selectable behavior. Something like this should work,

    import { useState } from 'react'
    import { Text, View } from 'react-native'
    
    const DelayedSelectableText = ({ children }) => {
      const [isSelectable, setIsSelectable] = useState(false)
    
      const handleLongPress = () => {
        // set a delay before enabling text selection
        const delay = 500 // adjust the delay time as needed
        setTimeout(() => {
          setIsSelectable(true)
        }, delay)
      }
    
      const handlePressOut = () => {
        // reset the state when the press is released
        setIsSelectable(false)
      }
    
      return (
        <Text
          selectable={isSelectable}
          onLongPress={handleLongPress}
          onPressOut={handlePressOut}
        >
          {children}
        </Text>
      )
    }
    
    // component usage...
    const App = () => {
      return (
        <View>
          <DelayedSelectableText>Some text</DelayedSelectableText>
        </View>
      )
    }
    
    export default App 
    
    Login or Signup to reply.
  2. Let see how it work :

    • we have Text component which render selected text and copy action on click
    export default function Text({ selectable, setShowPopup }) {
      const txt = "Text selected!";
    
      const copyTextToClipboard = (text) => {
        const textarea = document.createElement("textarea");
        textarea.value = text;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand("copy");
        document.body.removeChild(textarea);
        alert("Text copied to clipboard!");
        setShowPopup(false);
      };
    
      const handleCopyClick = () => {
        copyTextToClipboard(txt);
      };
    
      return (
        <>
          {selectable && (
            <>
              <div
                style={{
                  background: "#eaeaea",
                  padding: "10px",
                  border: "1px solid #ccc"
                }}
              >
                {txt}
              </div>
              <span onClick={handleCopyClick}>Click here to copy</span>
            </>
          )}
        </>
      );
    }
    
    
    • App component display Long press, press and hold mouse for 1000 ms, we call and reset once user click on "Click here to copy"
    import "./styles.css";
    import { useRef, useState } from "react";
    import Text from "./Text";
    
    export default function App() {
      const [showPopup, setShowPopup] = useState(false);
      const timeoutRef = useRef();
      const onLongPress = () => {
        timeoutRef.current = setTimeout(() => {
          setShowPopup(true);
        }, 1000);
      };
    
      const handleMouseUp = () => {
        clearTimeout(timeoutRef.current);
      };
    
      return (
        <div>
          <span
            onMouseDown={onLongPress}
            onMouseUp={handleMouseUp}
            style={{ userSelect: "none", cursor: "pointer" }}
          >
            Long press
          </span>
    
          {showPopup && <Text selectable={true} setShowPopup={setShowPopup}></Text>}
        </div>
      );
    }
    
    Login or Signup to reply.
  3. the Text component is selectable only when the user presses and hold on it for 500 milliseconds. This will prevent the selection popup from being triggered accidentally when scrolling or swiping

    import React, { useState } from 'react';
    
    const TextSelection = () => {
      const [isSelectable, setIsSelectable] = useState(false);
    
      const handleLongPress = () => {
        setIsSelectable(true);
        setTimeout(() => setIsSelectable(false), 500); // Set it to 500 milliseonds
      };
    
      return (
        <Text
          onLongPress={handleLongPress}
          selectable={isSelectable}
        >
          Hello World
        </Text>
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search