78

I have a Touchablehighlight that I need to position absolute, but it becomes unclickable after I do it.

What could cause this? It functions like it should if I dont have the position set to absolute.

mistenkt
  • 2,302
  • 3
  • 15
  • 19
  • This answer helped me. https://stackoverflow.com/questions/39250449/react-native-touchableopacity-not-working-inside-an-absolute-positioned-view/41946351#41946351 – I_User Mar 06 '18 at 11:40
  • I am facing to the same issue, with position absolute – Mahefa Jan 25 '20 at 13:17

18 Answers18

128

Solution was to change the order of the components.

What i originally had:

<TouchableHighLight><Text>Click me</Text></TouchableHighlight>
<View> .... </View>

This was the fix:

<View>...</View>
<TouchableHighLight><Text>Click me</Text></TouchableHighlight>
mistenkt
  • 2,302
  • 3
  • 15
  • 19
  • 9
    If I'm correct, the last element is shown above the first. Usually, that's how it loads elements to the DOM. In here, since the first element is `absolute`, the second element renders above it. When we change the order, the `absolute` element (Which is now the second element) loads on top. – THpubs Sep 10 '17 at 05:45
  • 7
    If you don't want to change the order of the components, an alternative is to change the `zIndex` of the Component you want to be on top of everything. Even a `zIndex: 1` will do it in most cases... – HedeH May 06 '18 at 08:34
  • 1
    I'm experiencing this and my problem is, my container must use position relative (the children components are absolute), so I can't swap the components' code position like answer in this thread. Do you have any suggestion? – Jeaf Gilbert Feb 04 '19 at 06:32
  • This is absolutely required for showing a component on top of FlatList. Thanks. – Greg R Taylor Aug 26 '19 at 12:39
  • @HedeH Not sure what use cases you'd would mind changing the order of the components, and have to use zIndex. It adds extra values, although it is explicit. Unfortunately, it means you can put components with absolute positioning anywhere in the component. Which is untidy. – Ben Butterworth Mar 26 '20 at 16:17
52

Dude just go and add zIndex : 1 to the view containing the buttons and boom you are done in most of the cases. Also note adding elevation adds shadow to android button and sometimes elevation may also be a issue if its added to parent and not added to child then the child button may not work.(Rare Case)

eg:

buttonContainers:
  {
    zIndex: 1,
    alignSelf: 'flex-end',
    position: 'absolute',
    top:5,
    right: 5,
    height: 40,
    borderWidth: 1,
    justifyContent: 'center',
    alignContent: 'center',
    width: 80
  },
Rishav Kumar
  • 4,979
  • 1
  • 17
  • 32
  • 2
    This is a very old post that was made before zIndex was introduced in RN. – mistenkt Aug 03 '18 at 11:04
  • 5
    Am sorry brother, I just made a comment so that If anyone new to react native faces the same problem and is unaware of the zIndex then it can help them a lot. : ) – Rishav Kumar Aug 03 '18 at 11:40
  • 2
    This just solved my issues with `react-native-vector-icons`. `zIndex: 1` was a critical bonus attribute. Otherwise having an `` component inside a `` causes a problem where the icon doesn't act as a hitspace but the area surrounding the icon did, so it made the button 100% garbage sauce. – agm1984 Nov 10 '18 at 23:17
  • 3
    Edit 1 : Sometimes zIndex is not only enough you have to add elevation to the child view above the parent view in android for it to work : ) – Rishav Kumar Jan 18 '19 at 10:02
  • 2
    this is not working, I have some touchables in the header of reactnavigation. and zIndex is not helping. – yernarun Jan 23 '19 at 14:05
  • share your code.. May be your touchable is hidden by another view.. May be elevation be a factor.. Check those – Rishav Kumar Jan 23 '19 at 14:37
  • @RishavKumar Yes true, I'm experiencing this and my problem is, my container must use position relative (the children components are absolute), so I can't swap the components' code position like answer in this thread. Do you have any suggestion? – Jeaf Gilbert Feb 04 '19 at 06:32
40

SOLVED:

I faced this issue today. I have solved it.

Import TouchableOpacity from react-native-gesture-handler instead of react-native.

Before:

import {TouchableOpacity} from "react-native";

After:

import {TouchableOpacity} from 'react-native-gesture-handler'
  • 3
    This is the best answer, I have been banging my head with this and realised that I've been importing the `TouchableOpacity` from `react-native-gesture-handler` and changed it to import from `react-native`. Yeah it is other way around, however it gave a spark and worked :p – Vimalraj Selvam Jun 08 '20 at 16:38
  • import {TouchableOpacity} from 'react-native-gesture-handler' did the job for me. Thanks! – yugantar kumar Jan 13 '21 at 11:54
  • This answer doesn't explain anything. It's an advise to rely on magic, it's not engineering. And the 'react-native-gesture-handler' has it's drawbacks (e.g. follow the links on this page) – x00 Jan 28 '21 at 12:31
  • 2
    Interestingly enough, for me the solution was the opposite, I switched from react-native-gesture-handler back to react-native's TouchableHighlight. – Mehmet Efe Akça Mar 02 '21 at 06:31
  • +1, for some reason mine also worked the other way around, the zindex/reordering answers did not do anything. – mxdi9i7 Mar 14 '21 at 23:47
  • the best answer – amani rose Apr 09 '21 at 12:16
14

use onPressIn instead of onPress

That made the area clickable!

Pavlo Savchuk
  • 167
  • 1
  • 5
10

I used TouchableOpacity inside an absolute view. The onPress function was not called after press it. But the opacity changed. I've tried all the above solutions, but none works.

My solutions is use onPressIn instead of onPress.

It seems like the inner action of Touchable* is weird in ReactNative when it's in an absolute view.

李华良
  • 224
  • 3
  • 10
5

After trying everything for two hours, the solution I found was to change my button position.

Before ...

  export default class Navbar extends Component {

  componentDidMount() {
    console.log(this.props);
  }

  render() {
    return (
      <View style={styles.content}>
        <TouchableOpacity
          onPress={this.props.openModal}
          style={styles.containerButton}
        >
          <Text>New</Text>
        </TouchableOpacity>
        <Text style={styles.textCenter}>Remember me</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  content: {
    paddingTop: 30,
    paddingBottom: 10,
    backgroundColor: '#81C04D',
    flexDirection: 'row'
  },
  containerButton: {
    position: 'absolute',
    top: 30,
    left: 8
  },
  textCenter: {
    flex: 1,
    textAlign: 'center',
    fontWeight: 'bold'
  }
});

After ...

export default class Navbar extends Component {

  componentDidMount() {
    console.log(this.props);
  }

  render() {
    return (
      <View style={styles.content}>
        <Text style={styles.textCenter}>Remember me</Text>
        <TouchableOpacity
          onPress={this.props.openModal}
          style={styles.containerButton}
        >
          <Text>New</Text>
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  content: {
    paddingTop: 30,
    paddingBottom: 10,
    backgroundColor: '#81C04D',
    flexDirection: 'row'
  },
  containerButton: {
    position: 'absolute',
    top: 30,
    left: 8
  },
  textCenter: {
    flex: 1,
    textAlign: 'center',
    fontWeight: 'bold'
  }
});

It works!!!

Marco Weber
  • 829
  • 10
  • 19
Anny Gutierrez
  • 139
  • 1
  • 3
4

My solutions is:

style:{
    zIndex: 1,
    position: 'absolute',
 }
4b0
  • 21,981
  • 30
  • 95
  • 142
3

use zIndex: 1 in view, it'll work.

<View style={{position : 'absolute', marginTop : 25, zIndex: 1}}>

More details can be found here :

How to use zIndex in react-native

jpm
  • 1,042
  • 2
  • 12
  • 36
3

For me, it works like:

import { TouchableOpacity } from 'react-native';

onPress, zIndex: 1, position: 'absolute'

3

One more solution.....

For me what worked was a combination of things....

import { TouchableOpacity } from 'react-native-gesture-handler'

and I WRAPPED my TouchableOpacity in a View.

before:

<TouchableOpacity onPress={()=> addCallback()}
    style={styles.addButtonHolder}
> 
    <PlusCircle style={styles.addButton} width={70} height={70} stroke={"white"} strokeWidth={3}/>
</TouchableOpacity>

after:

<View style={styles.addButtonHolder}>
    <TouchableOpacity onPress={()=> addCallback()}> 
        <PlusCircle style={styles.addButton} width={70} height={70} stroke={"white"} strokeWidth={3}/>
    </TouchableOpacity>
</View>

StyleSheet:

const styles = StyleSheet.create({

    addButtonHolder: {
        position: 'absolute',
        bottom: 70,
        right: 10,
        justifyContent: 'center', 
        alignItems: 'center',
        zIndex: 1,
    },
    addButton: {
        backgroundColor: '#b4cffa',
        borderRadius: 35
    }
})
Cyphire
  • 521
  • 1
  • 5
  • 8
2

This worked for me

import { TouchableOpacity } from 'react-native-gesture-handler'

and changed onPress to onPressIn

<TouchableOpacity onPressIn={() => console.log('clicked')}></TouchableOpacity>
2

My solution was to import TouchableHighlight from 'react-native'

It was originally imported from 'react-native-gesture-handler'

Alexander Danilov
  • 3,038
  • 1
  • 30
  • 35
1

This props help to disable ScrollView to catch all touches and let child handles

 keyboardShouldPersistTaps='always'
  • 'always', the keyboard will not dismiss automatically, and the scroll view will not catch taps, but children of the scroll view can catch taps.
  • 'handled', the keyboard will not dismiss automatically when the tap was handled by children of the scroll view (or captured by an ancestor).

https://reactnative.dev/docs/scrollview#keyboardshouldpersisttaps

Ali Mammadli
  • 385
  • 2
  • 10
1

When the position is absolute, TouchableHighlight or TouchableOpacity goes beneath from the surface. You have to add a higher zIndex value to the Container.

1

I ran into a similar problem, what I did was, I enclosed the whole thing into a new View and instead of giving 'absolute' position to the TouchableOpacity, I gave it to the parent View. That made the Opacity again clickable somehow. Here is the code snippet of before and after

My Code before

<TouchableOpacity
    onPress={() => {
        console.log("hah");
    }}
    style={{
        height: 50, width: 50,
        backgroundColor: 'rgb(90,135,235)',
        borderRadius: 25, alignItems: 'center',
        justifyContent: 'center', right: 0,position:'absolute'
    }}>
    <Image source={require('../assets/images/element-acorn-white.webp')}
        style={{ height: 30, width: 30, resizeMode: 'contain' }} />
</TouchableOpacity>

After Wrapping into a View with 'absolute'

<View style={{
    alignItems: 'flex-end', position: 'absolute',
    bottom: Dimensions.get('screen').height / 5
}}>
    <TouchableOpacity
        onPress={() => {
            console.log("hah");
        }}
        style={{
            height: 50, width: 50,
            backgroundColor: 'rgb(90,135,235)',
            borderRadius: 25, alignItems: 'center',
            justifyContent: 'center', right: 0,
        }}>
        <Image source={require('../assets/images/element-acorn-white.webp')}
            style={{ height: 30, width: 30, resizeMode: 'contain' }} />
    </TouchableOpacity>
</View>
0

He guy, I took a long time to find out why this happens. I tested a lot of the solution here. Two things worked for:

<View style={{  zIndex:0 }>
 ...
 <View style={{ position: 'absulote', zIndex:10 ,elevation: 10 }}>
    <TouchableHighLight><Text>Click me</Text></TouchableHighlight>
 </View>
 <View> .... </View>
 ...
</View>

If I am right, the reason for that is even that the button is shown, Android treats differently the layers of the Press events and you need to set a low level for the rest of your components. Defining a lower level for your wrapper component, all its children without this attribute will automatically inherit from the parent.

0

My problem was quite different, a backgroundColor style property was set on the container of my button. The color didn't work. I missed to remove this useless property. Finally, this backgroundColor was making an invisible sheet above my button. Removing it make it clickable again.

I faced the problem only on Android.

0

Add a zIndex to the component where you added position absolute. This solved the issue for me.

position: 'absolute',
zIndex: 1,

`

NavneetKaur0111
  • 117
  • 1
  • 8