React Native library for enhanced external keyboard support.
- ⚡️ The New Architecture is supported
- ⚡️ Bridgeless
| iOS | Android |
|---|---|
![]() |
![]() |
- Keyboard focus management and autofocus capabilities.
- Key press event handling.
- Focus management for
TextInputandPressablecomponents. - Customization of the
Halo EffectandtintColorfor iOS. defaultFocusHighlightEnabledsupport for Android.- Keyboard focus order.
- Focus Lock.
npm install react-native-external-keyboardiOS:
cd ios && pod install && cd ..The withKeyboardFocus HOC is a helper for integrating keyboard focus functionality. It significantly simplifies integration by wrapping the provided component in KeyboardFocusView and extending it with additional features, such as focus and blur events.
const KeyboardPressable = withKeyboardFocus(Pressable);
const KeyboardTouchable = withKeyboardFocus(TouchableOpacity);
const KeyboardButton = withKeyboardFocus(Button);
...
<TouchableOpacity
ref={ref}
onPress={...}
onLongPress={...}
onFocus={...}
onBlur={...}
style={styles.pressable}
containerStyle={styles.pressableContainer}
autoFocus
>
<Text>TouchableOpacity</Text>
</TouchableOpacity>After wrapping a Pressable or Touchable with withKeyboardFocus, you will be able to handle focus and blur events, control the tint color, apply focus and container focus styles, focus the component using a ref, or configure autoFocus.
| Props | Description | Type |
|---|---|---|
| onPress?: | Default onPress or keyboard-handled onPress |
((event: GestureResponderEvent) => void) | null | undefined |
| onLongPress?: | Default onLongPress or keyboard-handled onLongPress (Tab+M for iOS). |
((event: GestureResponderEvent) => void) | null | undefined |
| onPressIn:? | Default onPressIn or keyboard-handled onPressIn |
((event: GestureResponderEvent) => void) | null | undefined |
| onPressOut:? | Default onPressOut or keyboard-handled onPressOut |
((event: GestureResponderEvent) => void) | null | undefined |
| style?: | Styles the inner component | StyleProp<ViewStyle>; for Pressable: PressableProps['style'] |
| withPressedStyle?: | Enables the pressed style handler for custom components; always true for the standard Pressable. | boolean | undefined, false by default |
| focusStyle?: | Style applied to the inner component when focused | FocusStyle |
| containerStyle?: | Style for the container | StyleProp; |
| containerFocusStyle?: | Style applied to the container when focused | FocusStyle |
| onFocus?: | Handler called when the component is focused | () => void |
| onBlur?: | Handler called when the component loses focus | () => void |
| onFocusChange?: | Handler called when the component is focused or blurred | (isFocused: boolean, tag?: number) => void |
| onKeyUpPress?: | Handler for the key-up event | (e: OnKeyPress) => void |
| onKeyDownPress?: | Handler for the key-down event | (e: OnKeyPress) => void |
| autoFocus?: | Indicates if the component should automatically gain focus | `boolean |
| focusable?: | Indicates if the component can be focused by keyboard | `boolean |
| tintColor?: | Color used for tinting the component | string |
| tintType?: | Tint behavior type | 'default' | 'hover' | 'background' | 'none' |
| FocusHoverComponent?: | Component displayed on focus | | ReactElement | FunctionComponent | (() => ReactElement); |
| renderContent?: | Render prop for components whose children is itself a render function (e.g. Pressable). Receives the component's own render state merged with { focused: boolean }, so you can style content based on both the component state (e.g. pressed) and keyboard focus simultaneously. Only available when the wrapped component exposes a render-prop children. |
(state: ComponentRenderState & { focused: boolean }) => ReactNode |
| renderFocusable?: | Render prop available on any withKeyboardFocus-wrapped component. Replaces children and receives { focused: boolean }, allowing you to render different content based on keyboard focus state. Use this when the wrapped component does not expose a render-prop children. |
(state: { focused: boolean }) => ReactNode |
| group?: | Indicates if the component is a focusable group | boolean |
| haloEffect?: | Enables halo effect on focus (iOS only) | boolean |
| defaultFocusHighlightEnabled?: | Android only. Enables Android's default focus highlight for the focused native view. | boolean | undefined, default: true |
| haloCornerRadius?: | Corner radius of the halo ring (iOS only) | number |
| haloExpendX?: | Horizontal expansion of the halo ring in points (iOS only) | number |
| haloExpendY?: | Vertical expansion of the halo ring in points (iOS only) | number |
| ref?: | Provides a reference to the component, allowing programmatic focus control | { focus: () => void} |
| viewRef?: | Provides a reference to the underlying view component | RefObject<View> |
| onBubbledContextMenuPress | Handler for bubbled long-press events triggered by the context menu command (iOS only) | () => void; |
| triggerCodes?: | onPress and onLongPress trigger codes |
number[] | undefined, spacebar and enter by default |
| enableA11yFocus?: | Can be used to move the screen reader focus within the keyboard using ref.current.focus. |
boolean | undefined |
| screenAutoA11yFocus?: | Enables screen reader auto-focus functionality. | boolean | undefined |
screenAutoA11yFocusDelay?: |
Android only: Delay for screen reader autofocus. On Android, focus can only be applied after the component has rendered, which may take 300–500 milliseconds. | number | undefined, default: 300 |
exposeMethods?: |
List of exposed view methods | string[] | undefined, by default the following methods are exposed: 'blur', 'measure', 'measureInWindow', 'measureLayout', and 'setNativeProps'. |
| orderId? | A unique ID used for link target identification. | string |
| orderBackward? | ID of the target for backward navigation with "Tab + Shift". | string |
| orderForward? | ID of the target for forward navigation with "Tab". | string |
| orderLeft? | ID of the target for navigation to the left. | string |
| orderRight? | ID of the target for navigation to the right. | string |
| orderUp? | ID of the target for navigation upward. | string |
| orderDown? | ID of the target for navigation downward. | string |
| orderGroup? | The name of the group for index-based focus ordering. | string |
| orderIndex? | The order index of the element within its group. | number |
| lockFocus? | An array of directions to lock focus. | Array of 'left' | 'right' | 'up' | 'down' | 'forward' | 'backward' | 'first' | 'last' |
| ...rest | Remaining component props | Type of Component |
Pressable passes a { pressed } state to its children render prop. Use renderContent to access both pressed and the keyboard focused state at the same time:
const KeyboardPressable = withKeyboardFocus(Pressable);
<KeyboardPressable
onPress={onPress}
renderContent={({ pressed, focused }) => (
<View style={[
styles.button,
pressed && styles.pressed,
focused && styles.focused,
]}>
<Text>{pressed ? 'Pressed' : focused ? 'Focused' : 'Default'}</Text>
</View>
)}
/>TouchableOpacity and similar components do not expose a render-prop children, so renderContent is not available. Use renderFocusable instead — it receives only { focused }:
const KeyboardTouchable = withKeyboardFocus(TouchableOpacity);
<KeyboardTouchable
onPress={onPress}
renderFocusable={({ focused }) => (
<View style={[styles.button, focused && styles.focused]}>
<Text>{focused ? 'Focused' : 'Default'}</Text>
</View>
)}
/>Note
You may discover that long press on spacebar does not trigger a long press event on iOS. This is because iOS uses the Full Keyboard Access system that provides commands for interacting with the system. Rather than holding down the spacebar, you can use Tab+M (the default action for opening the context menu).
You can change Commands in: Full Keyboard Access -> Commands
KeyboardExtendedView is similar to withKeyboardFocus; it is also based on KeyboardExtendedBaseView and provides keyboard focus functionality. It can be useful for handling key presses or managing the focus of a group of components.
<KeyboardExtendedView>
<Text>Parent component</Text>
<KeyboardExtendedView>
<Text>Child component 1</Text>
</KeyboardExtendedView>
<KeyboardExtendedView>
<Text>Child component 2</Text>
</KeyboardExtendedView>
</KeyboardExtendedView>
| Props | Description | Type |
|---|---|---|
| onPress?: | Default onPress or keyboard-handled onPress |
((event: GestureResponderEvent) => void) | null | undefined |
| onLongPress?: | Default onLongPress or keyboard-handled onLongPress (Tab+M for iOS). |
((event: GestureResponderEvent) => void) | null | undefined |
| onPressIn:? | Default onPressIn or keyboard-handled onPressIn |
((event: GestureResponderEvent) => void) | null | undefined |
| onPressOut:? | Default onPressOut or keyboard-handled onPressOut |
((event: GestureResponderEvent) => void) | null | undefined |
| style?: | Style for the inner component | StyleProp<ViewStyle> |
| focusStyle?: | Style applied to the inner component when focused | FocusStyle |
| containerStyle?: | Style for the container | StyleProp; |
| containerFocusStyle?: | Style applied to the container when focused | FocusStyle |
| onFocus?: | Handler called when the component is focused | () => void |
| onBlur?: | Handler called when the component loses focus | () => void |
| onFocusChange?: | Handler called when the component is focused or blurred | (isFocused: boolean, tag?: number) => void |
| onKeyUpPress?: | Handler for the key-up event | (e: OnKeyPress) => void |
| onKeyDownPress?: | Handler for the key-down event | (e: OnKeyPress) => void |
| onBubbledContextMenuPress | Handler for bubbled long-press events triggered by the context menu command (iOS only) | () => void; |
| autoFocus?: | Indicates if the component should automatically gain focus | `boolean |
| focusable?: | Indicates if the component can be focused by keyboard | `boolean |
| tintColor?: | Color used for tinting the component | string |
| tintType?: | Tint behavior type | 'default' | 'hover' | 'background' | 'none' |
| FocusHoverComponent?: | Component displayed on focus | | ReactElement | FunctionComponent | (() => ReactElement); |
| group?: | Indicates if the component is a focusable group | boolean |
| haloEffect?: | Enables halo effect on focus (iOS only) | boolean |
| defaultFocusHighlightEnabled?: | Android only. Enables Android's default focus highlight for the focused native view. | boolean | undefined, default: true |
| haloCornerRadius?: | Corner radius of the halo ring (iOS only) | number |
| haloExpendX?: | Horizontal expansion of the halo ring in points (iOS only) | number |
| haloExpendY?: | Vertical expansion of the halo ring in points (iOS only) | number |
| triggerCodes?: | onPress and onLongPress trigger codes |
number[] | undefined, spacebar and enter by default |
| enableA11yFocus?: | Can be used to move the screen reader focus within the keyboard using ref.current.focus. |
boolean | undefined |
| screenAutoA11yFocus?: | Enables screen reader auto-focus functionality. | boolean | undefined |
screenAutoA11yFocusDelay?: |
Android only: Delay for screen reader autofocus. On Android, focus can only be applied after the component has rendered, which may take 300–500 milliseconds. | number | undefined, default: 300 |
exposeMethods?: |
List of exposed view methods | string[] | undefined, by default the following methods are exposed: 'blur', 'measure', 'measureInWindow', 'measureLayout', and 'setNativeProps'. |
| orderId? | A unique ID used for link target identification. | string |
| orderBackward? | ID of the target for backward navigation with "Tab + Shift". | string |
| orderForward? | ID of the target for forward navigation with "Tab". | string |
| orderLeft? | ID of the target for navigation to the left. | string |
| orderRight? | ID of the target for navigation to the right. | string |
| orderUp? | ID of the target for navigation upward. | string |
| orderDown? | ID of the target for navigation downward. | string |
| orderGroup? | The name of the group for index-based focus ordering. | string |
| orderIndex? | The order index of the element within its group. | number |
| lockFocus? | An array of directions to lock focus. | Array of 'left' | 'right' | 'up' | 'down' | 'forward' | 'backward' | 'first' | 'last' |
| ...rest | Remaining View props | View |
The TextInput component with keyboard focus support. This component allows the TextInput to be focused using the keyboard in various scenarios.
import { KeyboardExtendedInput } from 'react-native-external-keyboard';
...
<KeyboardExtendedInput
focusType="default"
blurType="default"
value={textInput}
onChangeText={setTextInput}
/>| Props | Description | Type |
|---|---|---|
| focusable?: | Boolean property whether component can be focused by keyboard | boolean \| undefined default true |
| onFocusChange?: | Callback for focus change handling | (isFocused: boolean) => void \| undefined |
| focusType?: | Focus type can be default, auto, or press. Based on investigation, Android and iOS typically have different default behaviors. On Android, the TextInput is focused by default, while on iOS, you need to press to focus. auto is used for automatic focusing, while keyboard focus targets the input. With press, you need to press the spacebar to focus an input. |
"default" \| "press" \| "auto" |
| blurType?: | Only for iOS. This defines the behavior for blurring input when focus moves away from the component. By default, iOS allows typing when the keyboard focus is on another component. You can use disable to blur input when focus moves away. (Further investigation is needed for Android.) | "default"\| "disable" \| "auto" |
| haloEffect?: | Enables halo effect on focus (iOS only) | boolean |
| defaultFocusHighlightEnabled?: | Android only. Enables Android's default focus highlight for the focused native view. | boolean | undefined, default: true |
| tintColor?: | Color used for tinting the component | string |
| style?: | Style for the inner TextInput | StyleProp<ViewStyle> |
| focusStyle? | Style applied to the inner TextInput when focused | FocusStyle |
| containerStyle | Style for the container | StyleProp |
| containerFocusStyle?: | Style applied to the container when focused | FocusStyle |
| tintType?: | Tint behavior type | 'default' \| 'hover' \| 'background' \| 'none' |
| FocusHoverComponent?: | Component displayed on focus | \| ReactElement \| FunctionComponent \| (() => ReactElement); |
| onSubmitEditing?: | Extended onSubmitEditing for multiline input |
(e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => void) |
| ...rest | Remaining TextInput props | TextInputProps |
import { KeyboardExtendedBaseView } from 'react-native-external-keyboard';
...
<KeyboardExtendedBaseView
onKeyDownPress={...}
onKeyUpPress={...}
focusable
>
<Text>Content</Text>
</KeyboardExtendedBaseView>| Props | Description | Type |
|---|---|---|
| focusable | Indicates if the component can be focused by keyboard | boolean | undefined |
| canBeFocused | (deprecated) Indicates if the component can be focused by keyboard | boolean | undefined |
| group | Indicates if the component is a focusable group | boolean |
| onFocus | Handler called when the component is focused | () => void |
| onBlur | Handler called when the component loses focus | () => void |
| onFocusChange | Handler called when the component is focused or blurred | (isFocused: boolean, tag?: number) => void |
| onKeyUpPress | Handler for the key-up event | (e: OnKeyPress) => void |
| onKeyDownPress | Handler for the key-down event | (e: OnKeyPress) => void |
| onContextMenuPress?: | Handler for long press events triggered by the context menu command (iOS only) | () => void; |
| onBubbledContextMenuPress | Handler for bubbled long-press events triggered by the context menu command (iOS only) | () => void; |
| haloEffect | Enables halo effect on focus (iOS only) | boolean | undefined |
| haloCornerRadius? | Corner radius of the halo ring (iOS only) | number |
| haloExpendX? | Horizontal expansion of the halo ring in points (iOS only) | number |
| haloExpendY? | Vertical expansion of the halo ring in points (iOS only) | number |
| autoFocus | Indicates if the component should automatically gain focus | boolean | undefined |
| tintColor | Color used for tinting the component | string |
| ref->focus | Command to programmatically focus the component | () => void; |
| orderId? | A unique ID used for link target identification. | string |
| orderBackward? | ID of the target for backward navigation with "Tab + Shift". | string |
| orderForward? | ID of the target for forward navigation with "Tab". | string |
| orderLeft? | ID of the target for navigation to the left. | string |
| orderRight? | ID of the target for navigation to the right. | string |
| orderUp? | ID of the target for navigation upward. | string |
| orderDown? | ID of the target for navigation downward. | string |
| lockFocus? | An array of directions to lock focus. | Array of 'left' | 'right' | 'up' | 'down' | 'forward' | 'backward' | 'first' | 'last' |
| ...rest | Remaining View props | View |
The KeyboardFocusGroup is a View-based component developed based on the iOS API. It can be used for defining focus groups or setting the tintColor globally.
<KeyboardFocusGroup
tintColor="orange">
<ScrollView
contentContainerStyle={styles.contentContainer}
style={styles.container}
>
...
</ScrollView>
</KeyboardFocusGroup>
<KeyboardFocusGroup
focusStyle={{ backgroundColor: 'green' }}
onFocusChange={(e) => console.log('green', e)}
groupIdentifier="green"
tintColor="green"
>
<Button>
</KeyboardFocusGroup>
<KeyboardFocusGroup
focusStyle={{ backgroundColor: 'yellow' }}
onFocusChange={(e) => console.log('yellow', e)}
groupIdentifier="yellow"
tintColor="yellow"
>
<Button>
</KeyboardFocusGroup>| Props | Description | Type |
|---|---|---|
| focusStyle? | Style applied to the inner component when it is focused | FocusStyle |
| onFocusChange?: | Handler called when the component is focused or blurred | (isFocused: boolean) => void; |
| onFocus?: | Handler called when the component is focused | () => void |
| onBlur?: | Handler called when the component loses focus | () => void |
| groupIdentifier?: | Relates to iOS focusGroupIdentifier: the identifier of the focus group to which this view belongs |
string |
Keyboard module to support soft keyboard dismissal.
import { Keyboard } from 'react-native-external-keyboard';
...
Keyboard.dismiss();
...This is needed for hiding the soft keyboard using a hardware keyboard. Additionally, the soft keyboard can be hidden from the settings or by pressing Alt + K.
Focus.Frame and Focus.Trap are two components that help manage and lock focus within specific areas of the screen.
- On iOS,
Focus.Trapuses the nativeaccessibilityViewIsModalproperty to keep the screen reader focus within a defined area. For stronger containment — such as preventing focus from reaching system elements like navigation bars or headers — passforceLock. It observes focus changes and moves focus back into the trap when it escapes. Note: because focus is corrected reactively, VoiceOver may briefly jump to an element outside the trap before being returned. - On Android, where no equivalent to
accessibilityViewIsModalexists, custom logic has been implemented as a workaround. By default, Android uses a custom Activity or Modal to limit focus. While using a Modal is considered the best practice for focus locking on Android, some scenarios—such as issues with React Native's Modal or library-specific constraints—may require alternative implementations.
The focus lock functionality should be used as a pair:
Focus.Frame: This component is used at the root level of a "screen" to detect focus leaks and ensure that focus remains contained.Focus.Trap: This component wraps the content area where focus should be explicitly locked.
| Prop | Description |
|---|---|
| ViewProps | Includes all standard React Native View properties, such as style, testID, etc. |
| forceLock? | iOS only. Strengthens focus containment beyond accessibilityViewIsModal by observing focus changes and returning focus back into the trap whenever it escapes to system elements (e.g. navigation bars, headers). Note: because focus is corrected reactively, VoiceOver may briefly jump to an element outside the trap before being returned. |
| lockDisabled? | Android only. Disables the focus lock when true. |
<Focus.Frame>
...
<Focus.Trap forceLock>
<Text accessibilityRole="header">Locked Area</Text>
<Button
title="Confirm"
accessibilityLabel="Confirm action"
/>
</Focus.Trap>
...
</Focus.Frame>Linking components could be the most logical way to define focus order. By using properties such as orderId and orderBackward, orderForward, orderLeft, orderRight, orderUp, and orderDown, you can customize the focus order according to your needs.
<View>
<Pressable
onPress={onPress}
orderId="0_0"
orderForward="0_2"
>
<Text>1</Text>
</Pressable>
<Pressable
onPress={onPress}
orderId="0_2"
orderBackward="0_1"
>
<Text>3</Text>
</Pressable>
<Pressable
onPress={onPress}
orderId="0_1"
orderForward="0_2"
orderBackward="0_0"
>
<Text>2</Text>
</Pressable>
</View>Important
orderId values are global. If the same IDs appear more than once on screen — e.g. in a list where each row renders the same component — duplicate IDs will cause incorrect focus jumps. Use KeyboardOrderFocusGroup or orderPrefix to keep IDs unique per instance.
When a link prop is used without any prefix, a console warning is shown reminding you to add one.
KeyboardOrderFocusGroup (auto namespace). Wraps a component tree and automatically namespaces all orderId values inside. Ideal for screens and containers where uniqueness is needed but the exact prefix doesn't matter.
// Each card gets its own isolated namespace
{items.map((item) => (
<KeyboardOrderFocusGroup key={item.id}>
<Pressable orderId="title" orderForward="action">…</Pressable>
<Pressable orderId="action" orderBackward="title">…</Pressable>
</KeyboardOrderFocusGroup>
))}Static namespace with groupId / orderPrefix. Use an explicit string when you need a stable, predictable namespace — for example, to create intentional focus links between two sibling components that know about each other.
// groupId on KeyboardOrderFocusGroup
<KeyboardOrderFocusGroup groupId="card_42">
<Pressable orderId="title" orderForward="action">…</Pressable>
<Pressable orderId="action" orderBackward="title">…</Pressable>
</KeyboardOrderFocusGroup>
// or orderPrefix directly on each component
<Pressable orderPrefix="card_42" orderId="title" orderForward="action">…</Pressable>
<Pressable orderPrefix="card_42" orderId="action" orderBackward="title">…</Pressable>You can find more examples here: Focus Link Order, DPad Order
| Props | Description | Type |
|---|---|---|
| orderId? | A unique ID used for link target identification. | string |
| orderBackward? | ID of the target for backward navigation with "Tab + Shift". | string |
| orderForward? | ID of the target for forward navigation with "Tab". | string |
| orderLeft? | ID of the target for navigation to the left. | string |
| orderRight? | ID of the target for navigation to the right. | string |
| orderUp? | ID of the target for navigation upward. | string |
| orderDown? | ID of the target for navigation downward. | string |
| orderPrefix? | Prefix prepended to this component's orderId and all order* target IDs. Use to namespace IDs in repeated components (lists, cards) or alongside a static groupId. |
string |
Linking is one of the best ways to set up focus order. However, there may be cases where you need to define the order of multiple elements within a group. As an alternative, you can use index-based ordering.
KeyboardOrderFocusGroup is a context provider that defines a named focus group. All children that declare orderIndex will be ordered within that group. You can optionally provide a groupId; if omitted, a unique ID is generated automatically.
import { KeyboardOrderFocusGroup } from 'react-native-external-keyboard';
<KeyboardOrderFocusGroup>
<View>
<Pressable onPress={onPress} orderIndex={0}>
<Text>First</Text>
</Pressable>
<Pressable onPress={onPress} orderIndex={2}>
<Text>Third</Text>
</Pressable>
<Pressable onPress={onPress} orderIndex={1}>
<Text>Second</Text>
</Pressable>
</View>
</KeyboardOrderFocusGroup>| Props | Description | Type |
|---|---|---|
| groupId? | Optional explicit group name. Auto-generated when omitted. | string |
| children? | Child components | ReactNode |
Alternatively, provide orderGroup directly on each component to skip the wrapper:
<Pressable orderGroup="main" onPress={onPress} orderIndex={0}>
<Text>First</Text>
</Pressable>
<Pressable orderGroup="main" onPress={onPress} orderIndex={1}>
<Text>Second</Text>
</Pressable>| Props | Description | Type |
|---|---|---|
| orderGroup? | The name of the group containing ordered elements. | string |
| orderIndex? | The order index of the element within the group. | number |
You can find more examples here: Focus Order via indexes
Finally, you can lock focus to specific directions.
<Pressable
lockFocus={['down', 'right']}
>
<Text>Lock Example</Text>
</Pressable>| Props | Description | Type |
|---|---|---|
| lockFocus? | An array of directions to lock focus. | Array of 'left' | 'right' | 'up' | 'down' | 'forward' | 'backward' | 'first' | 'last' |
Note
first and last are specific to iOS. When focus is blocked for forward and backward on iOS, it checks for the last and first elements to focus.
Functions in the A11yModule (KeyboardExtendedModule) have been deprecated. They appeared appropriate at the time, but with the new architecture and to improve usability, they have been replaced with ref actions.
Previous:
import { KeyboardExtendedModule } from 'react-native-external-keyboard';
KeyboardExtendedModule.setKeyboardFocus(ref); //or A11yModule.setKeyboardFocus(ref);Updated:
import { KeyboardExtendedPressable, type KeyboardFocus } from 'react-native-external-keyboard';
...
const ref = useRef<KeyboardFocus>(null);
...
const onPressForFocus = () => {
ref.current.focus()
}
<TouchableOpacity
ref={ref}
>
<Text>TouchableOpacity</Text>
</TouchableOpacity>
The specific method for iOS, setPreferredKeyboardFocus, has not been added so far because we now have the new feature autoFocus, which does not fit well with the new API and its approach. It is better to use autoFocus for focusing views on both Android and iOS.
If you truly need this method, please create a new issue, and we will consider how to return it.
Pressable changes
Unfortunately, the previous version of Pressable had many issues. For iOS, we cloned the entire Pressable component from React Native's source code, while for Android, we simply wrapped the component.
This led to two main problems:
- Difficulty in updating Pressable for iOS.
- Challenges in controlling styles.
For these reasons, we replaced Pressable with withKeyboardFocus(Pressable), as it was the only viable path forward to introduce new features.
It is believed that good naming can simplify usage and development. Based on this principle and for compatibility with 0.2.x, aliases were added. You can still use the old naming convention, and it will be maintained in future releases.
The map of aliases is provided below:
A11yModule -> KeyboardExtendedModule
Pressable -> KeyboardExtendedPressable
KeyboardFocusView -> KeyboardExtendedView
ExternalKeyboardView -> KeyboardExtendedBaseView
React and React Native packages have been updated in react-native-external-keyboard@0.8.0.
Unfortunately, the latest React Native versions (0.83.x and 0.84.x) have different types compared to previous versions, and the Pressable as well as KeyboardExtendedPressable props could be incompatible with local types because they have static TypeScript declarations based on the React Native 0.83.4 dependency.
In some cases, you may experience the following TypeScript problem:

It can be resolved by using a HOC, as it provides dynamic typing.
const KeyboardPressable = withKeyboardFocus(Pressable)
export const K = (props: PressableProps) => {
return <KeyboardPressable {...props} />;
}As well, it could be resolved by component redeclaration:
export {};
declare module 'react-native-external-keyboard' {
import type { PressableProps, ViewProps } from 'react-native';
import type { WithKeyboardFocusDeclaration } from 'react-native-external-keyboard/lib/typescript/src/types/WithKeyboardFocus';
export const Pressable: WithKeyboardFocusDeclaration<PressableProps, ViewProps['style']>
export const KeyboardExtendedPressable: WithKeyboardFocusDeclaration<PressableProps, ViewProps['style']>
}ToDo
export type OnKeyPress = NativeSyntheticEvent<{
keyCode: number;
unicode: number;
unicodeChar: string;
isLongPress: boolean;
isAltPressed: boolean;
isShiftPressed: boolean;
isCtrlPressed: boolean;
isCapsLockOn: boolean;
hasNoModifiers: boolean;
}>;- Refactor and Performance optimization
- Update
focusGroupIdentifierand implementKeyboardNavigationClusterfunctionality - Update
onPressandonLongPressforwithKeyboardFocus - Add functionality to control keyboard focus order.
- Verify and update
focusableanddisabledstates for iOS and Android. - Update
Readme.md. - Create the documentation.
Any type of contribution is highly appreciated. Feel free to create PRs, raise issues, or share ideas.
It has been a long journey since the first release of the react-native-external-keyboard package. Many features have been added, and a lot of issues have been fixed.
With that, I would like to thank the contributors, those who created issues, and the followers, because achieving these results wouldn't have been possible without you.
Thanks to the initial authors: Andrii Koval, Michail Chavkin, Dzmitry Khamitsevich.
Thanks to the contributors: João Mosmann, Stéphane.
Thanks to those who created issues: Stéphane, proohit, Rananjaya Bandara, SteveHoneckPGE, Wes
I really appreciate your help; it has truly helped me move forward!
MIT
Made with create-react-native-library

