110

How to detect if user close the keyboard in react native, I want to call a function when user closed the keyboard.

and if you can answer to detect keyboard is open too it will be appreciated, thanks.

I'm on the react native latest version 0.56

10 Answers 10

216

Thank you guys for your answers. Here is the hooks version if someone is interested:

const [isKeyboardVisible, setKeyboardVisible] = useState(false);

 useEffect(() => {
    const keyboardDidShowListener = Keyboard.addListener(
      'keyboardDidShow',
      () => {
        setKeyboardVisible(true); // or some other action
      }
    );
    const keyboardDidHideListener = Keyboard.addListener(
      'keyboardDidHide',
      () => {
        setKeyboardVisible(false); // or some other action
      }
    );

    return () => {
      keyboardDidHideListener.remove();
      keyboardDidShowListener.remove();
    };
  }, []);
Sign up to request clarification or add additional context in comments.

4 Comments

Hi @5-10. I've used this exact code in my App but for some reason neither of the events is fired. I'm using RN version 0.63.4 with android:windowSoftInputMode="adjustResize" in the manifest file. What could possibly cause it to not function properly? Thanks.
works as expected on RN 0.63.4 without any manifest changes.
when I try this I get the following Error: ReferenceError: Can't find variable: useEffect, any reason for this?
a little bit late but @yem you need to: import React, { useEffect, useState } from "react" and also import { Keyboard } from "react-native"
124

1. You can use Keyboard class from facebook.

Here is a sample code.

import React, { Component } from 'react';
import { Keyboard, TextInput } from 'react-native';

class Example extends Component {
  componentWillMount () {
    this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
    this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
  }
    
  componentWillUnmount () {
    this.keyboardDidShowListener.remove();
    this.keyboardDidHideListener.remove();
  }
    
  _keyboardDidShow () {
    alert('Keyboard Shown');
  }
    
  _keyboardDidHide () {
    alert('Keyboard Hidden');
  }
    
  render() {
    return (
      <TextInput
        onSubmitEditing={Keyboard.dismiss}
      />
    );
  }
}

###2. You can use some other npm dependency also, like react-native-keyboard-listener.

Import the component into the file you want to use it:

import KeyboardListener from 'react-native-keyboard-listener';

Use the component directly in your code. The component won't render anything

<View>
  <KeyboardListener
    onWillShow={() => { this.setState({ keyboardOpen: true }); }}
    onWillHide={() => { this.setState({ keyboardOpen: false }); }}
  />
</View>

To install this dependency run below command.

npm install --save react-native-keyboard-listener

Choose any you feel more convenient.

6 Comments

the first one i wanted that its works like a superman :D thanks man.
@Khemraj why i can't setState in function _keyboardDidShow or _keyboardDidHide?
@Khemraj It should be noted that option 2 is no longer working on android
I added Keyboard.addListener('keyboardDidShow', alert('keyboard')); to my app and it fires as soon as I open it. It's the same both in web view and on my Android device. Any ideas what I am doing wrong?
@stefanS yes. alert('keyboard') is being executed at the moment you bind the handler. to fire the alert when the handler is triggered, use Keyboard.addListener('keyboardDidShow', () => alert('keyboard'));
|
32

I wrapped this up in a hook:

import {useState, useEffect} from 'react';
import {Keyboard} from 'react-native';

export const useKeyboardVisible = () => {
  const [isKeyboardVisible, setKeyboardVisible] = useState(false);

  useEffect(() => {
    const keyboardDidShowListener = Keyboard.addListener(
      'keyboardDidShow',
      () => {
        setKeyboardVisible(true);
      },
    );
    const keyboardDidHideListener = Keyboard.addListener(
      'keyboardDidHide',
      () => {
        setKeyboardVisible(false);
      },
    );

    return () => {
      keyboardDidHideListener.remove();
      keyboardDidShowListener.remove();
    };
  }, []);

  return isKeyboardVisible;
};

The hook returns a boolean flag that can be used to apply logic conditionally or run any other effect needed.

6 Comments

Thanks this is a great answer - thank you!. One small modification that worked better for me was using keyboardWillShow and keyboardWillHide events instead. These events fire when the keyboard WILL appear so it gives time to, for instance, move a text input at the same time as the keyboard is loading.
Thanks for commenting mate! Yeah, that makes sense, you might have two different hooks for covering different scenarios in your app: useKeyboardDidShow useKeyboardWillShow could be a good naming for them
Oh yeah that's a great idea!
This is a really convenient solution - thanks @halbano!
This is the solution facebook should have provided rather than Keyboard.isVisible() since it's actually reactive. Bravo.
|
20

2023 Update

If you are using React native 0.71 or later you can use Keyboard.isVisible()

Example

import {Keyboard, Text, TextInput, StyleSheet, View} from 'react-native';

const Example = () => {
  return (
    <View style={style.container}>
      <TextInput
        style={style.input}
        placeholder="Click here…"
        onSubmitEditing={Keyboard.dismiss}
      />
      
      {Keyboard.isVisible() && <Text>Keyboard is visible</Text>}
    </View>
  );
};

const style = StyleSheet.create({
  container: {
    flex: 1,
    padding: 36,
  },
  input: {
    padding: 10,
    borderWidth: 0.5,
    borderRadius: 4,
  },
});

export default Example;

4 Comments

Great answer. Thank you, much less coding than setting up events/listeners
I tried this, but it's very unreliable for me. It works like 80% of the time. I suspect there is a race condition with the keyboard animating out where the last render might happen before Keyboard.isVisible() starts returning true. Since Keyboard.isVisible() isn't a reactive variable there will be no re-render if this happens so you end up with a broken state. Sometimes the view I try to hide still shows with the keyboard up and sometimes it's gone when the keyboard goes back down. :-(
Downvoted this, sorry. Keyboard.isVisible() will tell you if the keyboard is visible when calling it, but don't listen for changes. For that, you need the event listener
This is working perfectly.
11

I came across the usekeyboard hook found in @react-native-community/hooks

E.g.

import { useKeyboard } from '@react-native-community/hooks'
    
const keyboard = useKeyboard()
    
console.log('keyboard isKeyboardShow: ', keyboard.keyboardShown)
console.log('keyboard keyboardHeight: ', keyboard.keyboardHeight)

Source: https://github.com/react-native-community/hooks/blob/master/src/useKeyboard.ts

1 Comment

Good solution but there appears to be a delay in getting the current keyboard state
9

Improved version of @Khemraj 's answer (which worked great for me) with bound methods to the instance in order to be able to update the component's state from the listener and re-render.

import React, { Component } from 'react';
import { Keyboard, TextInput } from 'react-native';

class Example extends Component {

  state = {
      keyboardState: 'closed'
  }

  componentWillMount () {
    this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
    this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
  }

  componentWillUnmount () {
    this.keyboardDidShowListener.remove();
    this.keyboardDidHideListener.remove();
  }

  _keyboardDidShow = () => {
    this.setState({
        keyboardState: 'opened'
    });
  }

  _keyboardDidHide = () => {
    this.setState({
        keyboardState: 'closed'
    });
  }

  render() {
    return (
      <TextInput
        onSubmitEditing={Keyboard.dismiss}
      />
    );
  }
}

Comments

2

I used a small remix to the great answer from @halbano that may be useful to consider depending on your situation

export default function useKeyboardOffsetHeight(): number {
  const [keyBoardOffsetHeight, setKeyboardOffsetHeight] = useState(0);

  useEffect(() => {
    const keyboardWillShowListener = Keyboard.addListener(
      "keyboardWillShow",
      (e) => {
        setKeyboardOffsetHeight(e.endCoordinates.height);
      }
    );
    const keyboardWillHideListener = Keyboard.addListener(
      "keyboardWillHide",
      () => {
        setKeyboardOffsetHeight(0);
      }
    );

    return () => {
      keyboardWillHideListener.remove();
      keyboardWillShowListener.remove();
    };
  }, []);

  return keyBoardOffsetHeight;
}

keyBoardOffsetHeight vs isKeyboardVisible

I used integer keyBoardOffsetHeight instead of boolean isKeyboardVisible . Since it's often useful to move some of your other components based on the keyboard size. The offset is either 0 (hidden) or Y > 0 pixels (it is shown). Then I can use that in styling like so:

  const keyBoardOffsetHeight = useKeyboardOffsetHeight();
...
    <View
      style={{
        bottom: keyBoardOffsetHeight,
      }}
    >

keyboardWillShow vs keyboardDidShow

Secondly, I use keyboardWillShow events so that I can anticipate the keyboard appearing and fire my UI changes earlier.

The keyboardDidShow event fires once the keyboard has already appeared.

I also used keyboardWillHide instead of keyboardDidHide based on the same reasoning.

3 Comments

keyboardWillShow did not have the height for me. Had to use keyboardDidShow. WillShow is the intent/action; DidShow would have the result of the action.
If you are building something for Android this will not work. keyboardDidShow and keyboardDidHide only are available on Android.
My typescript installation doesn't provide the remove methods. However they work.
2

I think it's more simpler than using useEffect or other stuff. TextInput provides methods onFocus and onBlur.

import {TextInput} from "react-native";
    
const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);

<TextInput 
  value={someValue}
  onFocus={() => setIsKeyboardVisible(true)}
  onBlur={() => setIsKeyboardVisible(false)}
/>

1 Comment

Textnput can still be on focus while keyboard is hidden. Hiding the keyboard doesn't necessary trigger onBlur.
1

MobX version:

import { observable } from 'mobx'
import { EmitterSubscription, Keyboard } from 'react-native'

class KeyboardStore {
  @observable isKeyboardVisible = false
  keyboardSubs: EmitterSubscription[] = []

  subKeyboard() {
    this.keyboardSubs = [
      Keyboard.addListener('keyboardDidShow', () => this.isKeyboardVisible = true),
      Keyboard.addListener('keyboardDidHide', () => this.isKeyboardVisible = false),
    ]
  }

  unsubKeyboard() {
    this.keyboardSubs.forEach(sub => sub.remove())
    this.keyboardSubs = []
  }
}

and inside top level App component

  useEffect(() => {
    store.subKeyboard()
    return () => {
      store.unsubKeyboard()
    }
  }, [])

and check anywhere in your app with store.isKeyboardVisible.

Comments

0

All the thing already avalable in react-native Keyboard class

import React, { Component } from 'react';
import { Keyboard, TextInput } from 'react-native';

class Example extends Component {

    componentDidMount() {
        this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
        this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
        this.keyboardWillShowListener = Keyboard.addListener('keyboardWillShow', this._keyboardWillShow);
        this.keyboardWillHideListener = Keyboard.addListener('keyboardWillHide', this._keyboardWillHide);
    }

    componentWillUnmount() {
        this.keyboardDidShowListener.remove();
        this.keyboardDidHideListener.remove();
        this.keyboardWillShowListener.remove();
        this.keyboardWillHideListener.remove();
    }

    _keyboardWillShow() {
        console.log('Keyboard Showning')
    }

    _keyboardWillHide() {
        console.log('Keyboard Heding')
    }

    _keyboardDidShow() {
        alert('Keyboard Shown');
    }

    _keyboardDidHide() {
        alert('Keyboard Hidden');
    }

    render() {
        return (
            <TextInput
                onSubmitEditing={Keyboard.dismiss}
            />
        );
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.