Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Toast is not working within a Modal #985

Open
JLLLinn opened this issue Jun 26, 2017 · 67 comments
Open

[Bug] Toast is not working within a Modal #985

JLLLinn opened this issue Jun 26, 2017 · 67 comments

Comments

@JLLLinn
Copy link

JLLLinn commented Jun 26, 2017

react-native, react and native-base version

RN: 0.45.1
React:16.0.0-alpha.12
native-base: 2.1.5

Expected behaviour

Toast to be shown in react native Modal

Actual behaviour

The toast is not shown in react native Modal

Steps to reproduce (code snippet or screenshot)

Do Toast.show() in a Modal

Is the bug present in both ios and android or in any one of them?

No that I know of. This was working with RN on 0.44 and native-base on a lower version (I can't remember exactly which one, either 2.1.4 or 2.1.3)

@JLLLinn JLLLinn changed the title Toast is not working on RN 0.45 and native base on 2.1.5 [BUG] Toast is not working on RN 0.45 and native base on 2.1.5 Jun 26, 2017
@JLLLinn JLLLinn changed the title [BUG] Toast is not working on RN 0.45 and native base on 2.1.5 [Bug] Toast is not working on RN 0.45 and native base on 2.1.5 Jun 26, 2017
@JLLLinn JLLLinn changed the title [Bug] Toast is not working on RN 0.45 and native base on 2.1.5 [Bug] Toast is not working within a Modal Jun 26, 2017
@shivrajkumar
Copy link
Collaborator

@JLLLinn Check the latest of NativeBase i.e, v2.2.0

@laxgoalie392
Copy link

Was this verified that it was fixed? I think I'm experiencing it as well. My issue is that the Modal is covering the Toast so it isn't visible.

I'm on RN 0.46.4 and native base 2.2.1 and using the ios emulator.

Thanks!

@vovanmozg
Copy link

Same problem. I'm on RN 0.46.1 and native base 2.2.1 and using the ios emulator.

@mdebo
Copy link

mdebo commented Aug 24, 2017

Exactly the same problem using RN 0.47 and NativeBase 2.2.1.
Any news about it?
thanks!

@gianpaj
Copy link

gianpaj commented Nov 21, 2017

The Toast still appears behind the Modal (from React Native):

toast behind modal

the code is basically this:

import React from 'react';
import {
  Modal,
  Toast,
  Text,
  View,
} from 'react-native';

export default class LoginScreen extends React.Component<Props, State> {
  state = {
    modalVisible: false,
  }

  onResetPassword() {
    Toast.show({
      text: message,
      duration: 2000,
      position: "top",
      textStyle: { textAlign: "center" },
    });
  }    

  render() {
    return (
      <View>
        <Modal
          animationType="slide"
          transparent={false}
          visible={this.state.modalVisible}
          >
          <View>...</View>
        </Modal>
      </View>
    )
  }
}

Any suggestions?

I see there's something called zIndex as Layout Props - React Native

Using:

$ yarn list --depth=0 | grep 'native-base@\| react-native@'
├─ native-base@2.3.3
├─ react-native@0.50.3

Can something be done to the ToastContainer.js?
https://github.com/GeekyAnts/NativeBase/blob/master/src/basic/ToastContainer.js

@SupriyaKalghatgi
Copy link
Contributor

@gianpaj Looks like you are using React-Native-Seed boilerplate. Nice!
We will check this issue

@akhil-ga akhil-ga reopened this Nov 22, 2017
@akhil-ga akhil-ga added the bug label Nov 27, 2017
@idrakimuhamad
Copy link

I just want to add that I’m having this issue too with v 2.3.3

@gianpaj
Copy link

gianpaj commented Dec 13, 2017

FYI: this issue happens both on Android and iOS

@supercamilo
Copy link

Still present on 2.3.5

@gianpaj
Copy link

gianpaj commented Feb 10, 2018

I think I'm just going to use the Toast from ant-design-mobile.

My bad. Ant-Design Toast doesn't work. It also appears under the react-native Modal

@idrakimuhamad
Copy link

@gianpaj I'm also using antd-mobile for the datepicker. Perhaps I should take a look at their toast implementation too.

@SupriyaKalghatgi
Copy link
Contributor

@gianpaj What was the purpose of sharing graphs for commit-activity?

@ThomasLabstep
Copy link

Any hotfix for now with v2.3.10 ?

@AdrianMrn
Copy link

Any chance this will be fixed anytime soon?

@N9vn1njdf
Copy link

N9vn1njdf commented Apr 23, 2018

Сталкивался с этой проблемой недавно, решил следующим способом. Просто добавляем в Modal элемент Root, а в него весь контент который вам нужен

P.S. на английский переводить лень, главное ведь код

translation : Faced this problem recently, I decided in the following way. Just add the Root element to the Modal, and all the content you need is in it

import { Root, Container, Content } from 'native-base';

<Modal>
    <Root>
        <Container>
             <Content>
                  // .. modal content with toast
             </Content>
        </Container>
    </Root>
</Modal>

@doreentseng
Copy link

@Zeratyll Hey! It doesn't work for me at all, the toast still appears behind the Modal.

@michaellee8
Copy link

michaellee8 commented Jun 1, 2018

@doreentseng Tried @Zeratyll 's solution of putting <Root/> into <Modal/>, but it still didn't work.
@gianpaj Also tried to put style : { zIndex: 1000 } into Toast.show(), no effect as well.
All of the results are tested in a real iPad.
Tried Modal component from both original react-native and react-native-community, both of them didn't work. Will native-base provide its own modal component?
@SupriyaKalghatgi @shivrajkumar Dear collaborators, when can we get an fix?

@akhil-ga
Copy link
Contributor

akhil-ga commented Jun 20, 2018

checked this issue after merging PR #1700. Placing Root inside a modal component as suggested by @Zeratyll #985 (comment) is working after merging. See attached Gif.

Sample code

import React from 'react';
import { Modal } from "react-native";
import { createStackNavigator } from 'react-navigation';
import { Root, Container, Text, Header, Left, Body, Right, Title, Content, Button, Toast } from 'native-base';

class HomeScreen extends React.Component {

  state = { modalVisible: false }

  render() {
    return (
      <Container>
        <Header>
          <Left />
          <Body>
            <Title>Home screen</Title>
          </Body>
          <Right />
        </Header>

        <Content>
          <Button onPress={() => this.setState({ modalVisible: !this.state.modalVisible })} style={{ margin: 20 }}>
            <Text>Show modal</Text>
          </Button>
        </Content>

        <Modal
          animationType="slide"
          transparent={false}
          visible={this.state.modalVisible}>
          <Root>
            <Container style={{ padding: 20 }}>
              <Button style={{ margin: 20 }} onPress={() => Toast.show({
                text: 'Wrong password!',
                buttonText: 'Okay'
              })}>
                <Text>Show toast</Text>
              </Button>
              <Button style={{ margin: 20 }} onPress={() => this.setState({ modalVisible: !this.state.modalVisible })}>
                <Text>Hide modal</Text>
              </Button>
            </Container>
          </Root>
        </Modal>
      </Container>
    );
  }
}

const App = createStackNavigator({
  Home: {
    screen: HomeScreen
  },
}, {
    navigationOptions: {
      header: null
    }
  });

export default () => <Root>
  <App />
</Root>

Gif

toast-modal

Edit : As @gianpaj pointed out this may not be a viable option. Please see the below comment.

@gianpaj
Copy link

gianpaj commented Jun 20, 2018

Placing Root inside a modal component as suggested ... is working fine
@akhil-geekyants

This is not ideal or neither practical.

The state of Modal(s) should not be at the Root of an application. It should be where the Modal needs to appear, i.e. inside a screen/component/container.

If we had to do the way you suggest, the state of the Modal needs to pass down all the way to the Component in need (via props or in order ways).

I have to say this is not a viable option for any decent size application.

I don't know at the moment how to solve this, but pretty sure that's not it. Happy to be corrected if I'm wrong.

@akhil-ga
Copy link
Contributor

@gianpaj updated my comment.

@JeremyBradshaw7
Copy link

JeremyBradshaw7 commented Jul 5, 2018

Also having this problem. The Root workaround does work but also has an unwanted side-effect that windowed (non-fullscreen) modals no longer appear vertically centered, and no JSX adjustments appear to help.

@lewisflude
Copy link

The above Root fix didn't work for me as I'd like it to, as it completely ruins the vertical centring of the Toast

@Aleksandern
Copy link

My workaround for modals.

scene.js

<Scene>
  <ModalComponent />
</Scene>

ModalComponent.js

import Toast from 'mypathto/Toast';
class ModalComponent Component {
  
    showToast() {
        Toast.show({
          text: 'modal toast',
          position: 'bottom',
          duration: 3000
        });
    }

    render() {
        return (
            <Modal>
                <View>
                    <Button onPress={()=>this.showToast()}><Text>Toast<Text></Button>

                    <Toast
                      ref={c => {
                        if (c) Toast.toastInstance = c;
                      }}
                    />

                </View>
            </Modal>
        )
    }
}

mypathto/Toast.js

import {
  Toast as ToastNB,
} from "native-base";

class Toast extends ToastNB {
}

export default Toast;

@amitdninawe
Copy link

amitdninawe commented Jan 10, 2022

Adding a blank Toast <Toast /> inside the modal view works. I have tested this in android only. Please give it a shot and let me know

@rs6g10
Copy link

rs6g10 commented Jan 11, 2022

Neither <Toast /> nor Root exist as components in version 3.2.2. There aren't any better workarounds for this. Can we get this issue reopened please?

@rs6g10
Copy link

rs6g10 commented Jan 11, 2022

Since Root no longer exists, a quick workaround is wrapping the entire Modal content in NativeBaseProvider.

I'm using the following workaround for version 3.2.2 to see toasts in my react-native-modal:

<RNModal
   isVisible={modalVisible}
   deviceWidth={deviceWidth}
   deviceHeight={deviceHeight}
   coverScreen={true}
   style={styles.modal}
    >
      <NativeBaseProvider>
        <View style={styles.modalHeader}>
          <TouchableOpacity
            style={{ marginTop: 48 }}
          >
            <Icon
              name='close'
              as={MaterialCommunityIcons}
              onPress={onClose}
              size={12}
              style={{
                right: 16,
                alignSelf: 'flex-end',
              }}
            />
          </TouchableOpacity>
          <View style={styles.modalBody}>
            {children}
          </View>
        </View>
      </NativeBaseProvider>
</RNModal>

@md-rehman
Copy link
Collaborator

I'm reopening this issue, and we'll keep it on high priority.

@md-rehman md-rehman reopened this Jan 13, 2022
@Drakeoon
Copy link

Drakeoon commented Mar 11, 2022

@md-rehman I would also love this feature to be back, ideally a separate API to configure Toast's root element.

Have you guys started working on it already? I would love to help or take care of that issue, so that we can have it back on our project 💪🏻

@masrurimz
Copy link

masrurimz commented Mar 20, 2022

Since Root no longer exists, a quick workaround is wrapping the entire Modal content in NativeBaseProvider.

I'm using the following workaround for version 3.2.2 to see toasts in my react-native-modal:

<RNModal
   isVisible={modalVisible}
   deviceWidth={deviceWidth}
   deviceHeight={deviceHeight}
   coverScreen={true}
   style={styles.modal}
    >
      <NativeBaseProvider>
        <View style={styles.modalHeader}>
          <TouchableOpacity
            style={{ marginTop: 48 }}
          >
            <Icon
              name='close'
              as={MaterialCommunityIcons}
              onPress={onClose}
              size={12}
              style={{
                right: 16,
                alignSelf: 'flex-end',
              }}
            />
          </TouchableOpacity>
          <View style={styles.modalBody}>
            {children}
          </View>
        </View>
      </NativeBaseProvider>
</RNModal>

Could you provide example to customize default theme of native base modal, action sheet and other overlay component so, toast will be appeared on the top of it

@stale
Copy link

stale bot commented May 25, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label May 25, 2022
@Oct4Pie
Copy link

Oct4Pie commented May 30, 2022

I have the same issue. The toast doesn’t appear on the modal. No solutions yet.

@stale stale bot removed the stale label May 30, 2022
@iooi
Copy link

iooi commented Jun 3, 2022

+1

@zzyjiaxinmomo
Copy link

is there any solution now?

@Viraj-10
Copy link
Collaborator

Hi @zzyjiaxinmomo @iooi @Oct4Pie, Can you provide small snack example ?

@Oct4Pie
Copy link

Oct4Pie commented Jul 1, 2022

Hi @zzyjiaxinmomo @iooi @Oct4Pie, Can you provide small snack example ?

Hello, @Viraj-10. Here it is:

import React from "react";
import {
  Text,
  HStack,
  Center,
  Switch,
  useColorMode,
  NativeBaseProvider,
  extendTheme,
  VStack,
  Modal,
  Input,
  FormControl,
  Button,
  useToast,
} from "native-base";

const config = {
  useSystemColorMode: false,
  initialColorMode: "dark",
};

export const theme = extendTheme({ config });

export default function App() {
  const [show, setShow] = React.useState(false);
  const toast = useToast();

  return (
    <NativeBaseProvider>
      <Center
        _dark={{ bg: "blueGray.900" }}
        _light={{ bg: "blueGray.50" }}
        px={4}
        flex={1}
      >
        <VStack space='3' >
          <Modal onClose={() => setShow(false)} isOpen={show}>
            <Modal.Content>
              <Modal.CloseButton />
              <Modal.Header>Sign In</Modal.Header>
              <Modal.Body>
                Please enter your credentials to proceed
                <FormControl mt={{
                  'base': '3',
                  'lg': '4',
                  '2xl': '5',
                }}>
                  <FormControl.Label>Email</FormControl.Label>
                  <Input />
                </FormControl>
                <FormControl mt={{
                  'base': '3',
                  'lg': '4',
                  '2xl': '5',
                }}>
                  <FormControl.Label>Password</FormControl.Label>
                  <Input />
                </FormControl>
              </Modal.Body>
              <Modal.Footer>
                <Button onPress={() => {
                  toast.show({
                    // variant: "solid",
                    description: "You are signed in!",
                  })
                  // setShow(false);
                }}>
                  Sign In
                </Button>
              </Modal.Footer>
            </Modal.Content>
          </Modal>
          <VStack space={8} alignItems="center">
            <Button w="104" onPress={() => {
              setShow(!show);
            }}>
              Sign In Modal
            </Button>
          </VStack>
          <ToggleDarkMode />
        </VStack>
        <SignInModal />

      </Center>
    </NativeBaseProvider>
  );
}

const SignInModal = () => {
  const [show, setShow] = React.useState(false);
  const toast = useToast();
  return <VStack space='3' >

    <Modal onClose={() => setShow(false)} isOpen={show}>
      <Modal.Content>
        <Modal.CloseButton />
        <Modal.Header>Sign In</Modal.Header>
        <Modal.Body>
          Please enter your credentials to proceed
          <FormControl mt={{
            'base': '3',
            'lg': '4',
            '2xl': '5',
          }}>
            <FormControl.Label>Email</FormControl.Label>
            <Input />
          </FormControl>
          <FormControl mt={{
            'base': '3',
            'lg': '4',
            '2xl': '5',
          }}>
            <FormControl.Label>Password</FormControl.Label>
            <Input />
          </FormControl>
        </Modal.Body>
        <Modal.Footer>
          <Button onPress={() => {
            toast.show({
              variant: "solid",
              description: "You are signed in!",
            })
            // setShow(false);
          }}>
            Sign In
          </Button>
        </Modal.Footer>
      </Modal.Content>
    </Modal>
    <VStack space={8} alignItems="center">
      <Button onPress={() => {
        setShow(!show);
      }}>
        Sign In Modal (component)
      </Button>
    </VStack>
  </VStack>;
}

function ToggleDarkMode() {
  const { colorMode, toggleColorMode } = useColorMode();
  return (
    <HStack space={2} alignItems="center">
      <Text>Dark</Text>
      <Switch
        isChecked={colorMode === "light"}
        onToggle={toggleColorMode}
        aria-label={
          colorMode === "light" ? "switch to dark mode" : "switch to light mode"
        }
      />
      <Text>Light</Text>
    </HStack>
  );
}

As you can see, useToast does not work in the default App function. I need the modal to be in App since the state variables must be passed to other screens. I couldn't find a way to solve this issue and wrote a similar component to toast, but it's not as efficient.

@Viraj-10
Copy link
Collaborator

Hi All, Let me explain what's going on internally.
On Android, we use RN Modal and on IOS we use Overlay Component which is View with absoluteFill Styling.
Since IOS doesn't support multiple Modal we have to render an Overlay.
Now, whenever you render RN modal on android it mounts on top of the application but toast is again an overlay. So it renders below RN Modal.
Solution
Complete remove RN Modal and use Overlay instead. (Difficulties Accessibility).

@danimayfield
Copy link

Is there any solution to this yet?

@bilalalbkre
Copy link

that solution worked in my case
https://github.com/calintamas/react-native-toast-message/blob/main/docs/modal-usage.md
just add "Toast" tag inside the Modal component

@sturmenta
Copy link

sturmenta commented Mar 27, 2023

I've been struggling with this for a while and found a pretty acceptable solution! 🥳

  • examining how the Toast component receives its properties, I found that the component could receive a property called _overlay

Screenshot 2023-03-27 at 16 53 51

And the Overlay component receive a style prop

Screenshot 2023-03-27 at 17 06 41

const theme = extendTheme({
 {...}
  components: {
    Toast: {
      defaultProps: {
        _overlay: { style: { zIndex: 999 } }
      }
    }
  }
});

then, by passing a high zIndex, the toast is displayed above the Modal! 🎉

Screenshot 2023-03-27 at 17 08 41


note: using Modal & Toast both from native-base v3.4.23

@astaninivan1
Copy link

astaninivan1 commented Apr 17, 2023

"useRNModalOnAndroid: false", default for component "Modal" helped

const theme = extendTheme({
  components: {
    Modal: {
      defaultProps: {
        _overlay: {
          useRNModalOnAndroid: false,
        },
      },
    },
  }
});

@sturmenta
Copy link

"useRNModalOnAndroid: false", default for component "Modal" helped

const theme = extendTheme({
  components: {
    Modal: {
      defaultProps: {
        _overlay: {
          useRNModalOnAndroid: false,
        },
      },
    },
  }
});

your initial problem was in android or iOS?

@tonytony2020
Copy link

calintamas/react-native-toast-message it is very simple and easy to use.

it's 2023, any updates to fix this bug?

@Aryk
Copy link

Aryk commented Sep 10, 2023

In short, no...they slowly (and quietly) moved on to another project - https://ui.gluestack.io/

@levon-zakarian
Copy link

After trying everything here and with no luck, I still kept struggling with this for a long time, and after checking how Toast works multiple times I've come across a workaround that finally worked for me.

So under the hood it is using useContext and there is a Provider that is also exported in native-base called ToastProvider, and when you use it Inside the Modal it works as expected.

Here's a sample code:

Container.tsx

import { useState } from "react";

// components
import { Button, Center, VStack, useToast } from "native-base";
import ModalToast from "./ModalToast";

const Container = () => {
  const toast = useToast();
  const [isOpen, setIsOpen] = useState(false);

  const closeModal = () => {
    setIsOpen(false);
  };

  const openModal = () => {
    setIsOpen(true);
  };

  const showToast = () => {
    toast.show({ title: "A Regular Toast In App" });
  };

  return (
    <Center flex={1}>
      <VStack space={5}>
        <Button onPress={openModal}>Open Modal</Button>
        <Button onPress={showToast}>Show Outer Toast</Button>
      </VStack>

      <ModalToast isOpen={isOpen} onClose={closeModal} />
    </Center>
  );
};

export default Container;

ModalToast.tsx

import {
  Button,
  Center,
  HStack,
  Modal,
  ToastProvider,
  useToast,
} from "native-base";

const ModalContent = ({ onClose }: { onClose: () => void }) => {
  const toast = useToast();

  const showToast = () => {
    toast.show({ title: "A Toast over the modal" });
  };

  return (
    <Center flex={1}>
      <HStack space={4}>
        <Button onPress={showToast}>Show Toast</Button>
        <Button onPress={onClose}>Close Modal</Button>
      </HStack>
    </Center>
  );
};

interface ModalToastProps {
  isOpen: boolean;
  onClose: () => void;
}

const ModalToast = ({ isOpen, onClose }: ModalToastProps) => (
  <Modal
    isOpen={isOpen}
    animationPreset="slide"
    bg="gray.200"
    onClose={onClose}
    safeAreaBottom
  >
    <ToastProvider>
      <ModalContent onClose={onClose} />
    </ToastProvider>
  </Modal>
);

export default ModalToast;

The only issue is that the App toast still stays under the modal, as the one inside the modal is another provider so it displays whole other Toast.

Screen.Recording.2023-10-16.at.13.35.34.mov

Using both Modal & Toast from native-base v3.4.28

Hope this will be of help.

@jnariai
Copy link

jnariai commented Oct 25, 2023

A workaround is to set RNModal to false

      <Modal
        _overlay={{
          useRNModal: false,
          useRNModalOnAndroid: false,
        }}
      >

@soemarko
Copy link

I mean, realistically, NativeBase is abandoned. I've just moved all Toast to react-native-toast-message. Bit by bit, I'm slowly removing native-base from my project.

I'll never go to gluestack if this how they handle projects. They'll abandon gluestack too as soon as a new shiny thing coming down the line.

@iooi
Copy link

iooi commented Oct 28, 2023

Can we get the refund?

@LordAsmodey
Copy link

I have my own separate context provider for toasters, which wraps the parts of my application I need. And as I see, everything now works as it should on iOS devices. And for Android, the setup that astaninivan1 suggested helped me.
#985 (comment)
But the fact that the NB has not been updated for a year makes me sad...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests