24

Hi I want to wrap TouchableOpacity within a Text as I want to make some of the text clickable. When I wrap everything within a Text it looks perfect and that is how I want it to look.

 <Text 
   style={{color: colors.black,
           fontSize: 12,
           fontWeight: 'normal',
           marginTop: 10,
           lineHeight: 18}}>
      {strings.loginPrivacyTermsCondOne} 
        <Text style={{color: colors.primaryColor,
                      fontSize: 12,
                      fontWeight: 'normal',}}>
          {strings.loginPrivacyTermsCondTwo}
        </Text>
          {strings.loginPrivacyTermsCondThree} 
        <Text style={{color: colors.primaryColor,
                      fontSize: 12,
                      fontWeight: 'normal'}}>
          {strings.loginPrivacyTermsCondFour}
        </Text>

          {/* <TouchableOpacity onPress={ this.termsOfService }>
            <Text style={{color: colors.primaryColor,
                          fontSize: 12,
                          fontWeight: 'normal',}}>
              {strings.loginPrivacyTermsCondFour}
            </Text>
          </TouchableOpacity> */}
      </Text>

When I add TouchableOpacity it does not work.

I tried adding it in a view then it works fine and I am able to add TouchableOpacity but from UI perspective, they are not aligned properly.

Here is the screenshot showing just with Text where TouchableOpacity does not work and second bit is within the View where TouchableOpacity does work but does not look right.

enter image description here

How can make it look right as the first bit. any suggestions much appreciated.

Thanks R

David Schumann
  • 13,380
  • 9
  • 75
  • 96
BRDroid
  • 3,920
  • 8
  • 65
  • 143

1 Answers1

40

You can nest Text elements, and assign onPress handlers on each nested Text element you want to make pressable (a link).

See below. There is an outer text element, and inside is another text element, the child text element has an onPress handler, if you run this, you'll see 'But this is!' executes the onPress handler when you press it, no need for a Touchable* element.

<Text style={{color: '#000'}}> 
     This part is not clickable 
     <Text onPress={() =>
           {alert('but this is');}}
           style={{color: '#00F'}}>
     But this is!
     </Text> 
     but this isn't
</Text>

You could make a style to place on any Text elements which have the/a onPress handler, to make them a different colour, as in your example image.

Note, this is much like HTML, where you would nest anchor tags inside a p element, for example;

<p>
    This part is not clickable 
    <a href="https://google.com"> but this is</a>
    but this isn't
</p>

In your example, it'd be something like this (untested):

<Text style={{color: colors.black,
              fontSize: 12,
              fontWeight: 'normal', 
              marginTop: 10,
              lineHeight: 18}}>
        {strings.loginPrivacyTermsCondOne} 
        <Text style={{color: colors.primaryColor,
                      fontSize: 12,
                      fontWeight: 'normal',}}>
          {strings.loginPrivacyTermsCondTwo}
        </Text>
          {strings.loginPrivacyTermsCondThree} 
        <Text style={{color: colors.primaryColor, 
                      fontSize: 12,
                      fontWeight: 'normal'}}>
          {strings.loginPrivacyTermsCondFour}
        </Text>

          <Text onPress={ this.termsOfService } 
                style={{color: colors.primaryColor,
                        fontSize: 12, 
                        fontWeight: 'normal'}}>
              {strings.loginPrivacyTermsCondFour}
          </Text> 
      </Text>

In response to your comment, here's a knock-up example of changing the colour, after the link has been clicked.

In short, I've added a boolean field on state, once the text gets pressed, I update that state variable to be true, the text element's style value then has a ternary operator, which decides what colour to render the text in, in my example it will show as 'colors.primaryColor' if it's not been pressed yet, and 'red' once it has been clicked.

class Foo extends Component {

    constructor (props) {
        super(props);

        this.state = {
            privacyClicked: false //Track if they have clicked privacy
        };
    }

    render () {

        return (
             <Text onPress={ () =>{
    this.setState({
        privacyClicked: true
    });
}} style={{color: (this.state.privacyClicked ? colors.primaryColor : 'red'), 
           fontSize: 12,
           fontWeight: 'normal'}}>
    {strings.loginPrivacyTermsCondFour}
</Text> 
        );
    }
}

PS, formatting on the example Text isn't great.

David Schumann
  • 13,380
  • 9
  • 75
  • 96
Lee Brindley
  • 6,242
  • 5
  • 41
  • 62
  • Hello Lee, thank you for that, yes onPress on text is the solution I need very simple thank you. But one thing tough could you suggest how to change the color of the text when clicked? so that it appears as if it is clicked – BRDroid Sep 04 '18 at 14:45
  • Given you an example in my answer, if this helped, please upvote and accept thew answer :) – Lee Brindley Sep 04 '18 at 14:59
  • while this works great of iOS, there is no highlighting or opacity change when pressed on Android. Any suggestions? – Gianfranco P. Nov 21 '18 at 09:29
  • 3
    This doesn't seem to work on screenreaders very well. It just reads everything as plain text instead of a as pressable – Waltari Nov 12 '20 at 12:59
  • In this case accessibly is not working correctly. It is identifying as one element in voiceover – Jak Nov 12 '20 at 15:05
  • TIL Text has on onPress prop, thanks! – Staghouse Jan 31 '22 at 00:25