Vertically align Pressable inside a Text component

Viewed 1301
<View
  style={{
    flexDirection: "row",
  }}
>
  <Text
    style={{
      flex: 1,
    }}
  >
    By continuing, you agree to our{" "}
    <Pressable
      onPress={...}
    >
      <Text>
        Terms of Service
      </Text>
    </Pressable>
  </Text>
</View>

"Terms of Service" is printed higher than "By continuing, you agree to our". How do I vertically align them? Or more precisely - how do I get the Pressable Text to vertically align to the bottom? enter image description here

5 Answers

This is a bug in React Native itself. There are several open reports of this bug on React Native's GitHub, but the chances of it being fixed don't look good:


In the meantime the best workaround appears to be:

  • If you don't need Pressable's pressed state, use Text instead of Pressable (as the asker did: https://stackoverflow.com/a/66590787/568458)
  • If you do need pressed state, Text doesn't support the required onPressIn/Out handlers. However, TouchableWithoutFeedback does support those, and works by injecting props into its child so the Text will remain Text with no wrapping View. Wrap a Text in TouchableWithoutFeedback and pass the touchable onPress with onPressIn and onPressOut handlers and store the pressed state yourself.

Crude example (you might want to add support for focus state etc):

/**
 * Like a simplified Pressable that doesn't look broken inline in `Text`
 */ 
const TextButton = ({ children, onPress, style } => {
  const [pressed, setPressed] = useState(false)
  const onPressIn = () => setPressed(true)
  const onPressOut = () => setPressed(false)

  // TouchableWithoutFeedback modifies and returns its child; this returns `Text`
  // plus press in/out events attached that aren't supported by Text directly.
  return (
    <TouchableWithoutFeedback
      onPress={onPress}
      onPressIn={onPressIn}
      onPressOut={onPressOut}
    >
      <Text style={typeof style === 'function' ? style({ pressed }) : style}>
        {typeof children === 'function' ? children({ pressed }) : children}
      </Text>
    </TouchableWithoutFeedback>
  )
}

Warning: if you're also using React Native Web and React Navigation, don't use the TouchableWithoutFeedback approach on Web, use pure Pressable on web, because React Navigation's navigate functions don't reliably work when passed to Touchable*s on Web due to a quirk of how the event handlers are set up (but they do work in Pressable), and this issue doesn't exist on Web.

Ended up doing this differently, using the onPress property of the <Text> component and finally wrapping all <Text> components in another <Text> component to have a proper line break:

<View>
  <Text>
    <Text>
      By continuing, you agree to our{" "}
    </Text>
    <Text onPress={() => {...}}>
      Terms of Service
    </Text>
    <Text>
      {" "}and our{" "}
    </Text>
    <Text onPress={() => {...}}>
      Privacy Policy
    </Text>
  </Text>
</View>

The snippet below should work but hard to understand without giving a shot. If you can provide screenshots I can help more in sake of getting a more proper result.

<View>
  <Text style={{
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center'
  }}>
    By continuing, you agree to our{" "}
    <Pressable
      onPress={() => {
        navigate("LegalStack", { screen: "Terms" });
      }}
    >
      <Text style={{margin: 'auto'}}>
        Terms of Service
      </Text>
    </Pressable>
  </Text>
</View>

By default the flexDirection is column. Change it to flexDirection:"row"

I found a very hackidy-hack solution...

<Text selectable={true}>
     <Text>if you click</Text>
     <TouchableOpacity
       style={{flexDirection: 'row'}}
       onPress={() => Linking.openURL("https://www.google.com")}
     >
         <Text
           style={{
             alignSelf: 'flex-end',
             marginBottom: -4,
           }}
         >
             here
         </Text>
     </TouchableOpacity>
     <Text>, it will open google</Text>
</Text>
Related