react-native-keyboard-flatlist
v1.0.0
Published
A cross-platform React Native FlatList that supports hardware keyboard navigation (Up, Down, Left, Right, Enter) for iOS, Android, and Web.
Maintainers
Readme
react-native-keyboard-flatlist
A cross-platform React Native FlatList component that supports native hardware keyboard and TV remote navigation (Arrow Up, Arrow Down, Arrow Left, Arrow Right, Enter, D-Pad Center).
Built using the Expo Modules API and modern React Native architecture, it seamlessly intercepts physical key presses on iOS, Android (including Android TV / Fire TV), and Web.
Features
- Cross-Platform: Works on iOS (via
UIKeyCommand), Android (including TV D-Pads viadispatchKeyEvent), and Web. - TV & Gamepad Remote Ready: Native support for D-Pad Center (
KEYCODE_DPAD_CENTER), Gamepad A (KEYCODE_BUTTON_A), Numpad Enter, and Arrow keys. - 2D Grid Layout Navigation: Full support for multi-column grids (
numColumns > 1), automatically calculating row and column movement. - Auto-Scrolling: Automatically scrolls to center the currently focused item.
- Circular Looping: Optional
loopprop to wrap around navigation from end to start. - Pause/Resume Control: Easily disable keyboard interception when dialogs, modals, or text inputs are open via
enabled. - Accessibility Friendly: Passes
isFocusedtorenderItemso you can apply styles and updateaccessibilityState.
Installation
npm install react-native-keyboard-flatlistOr using Yarn:
yarn add react-native-keyboard-flatlistExpo Projects
This library includes an Expo Config Plugin to automatically inject D-Pad key interception into Android's MainActivity.
Add it to your app.json or app.config.js:
{
"expo": {
"plugins": ["react-native-keyboard-flatlist"]
}
}Then rebuild your app:
npx expo prebuild
npx expo run:android
npx expo run:iosUsage
Simple List Navigation
Replace standard FlatList with KeyboardFlatList. Your renderItem callback receives isFocused.
import React from 'react';
import { Text, TouchableOpacity, StyleSheet } from 'react-native';
import { KeyboardFlatList } from 'react-native-keyboard-flatlist';
const DATA = [
{ id: '1', title: 'First Item' },
{ id: '2', title: 'Second Item' },
{ id: '3', title: 'Third Item' },
];
export default function App() {
const handleItemPress = (item, index) => {
console.log('Pressed item:', item.title, 'at index:', index);
};
return (
<KeyboardFlatList
data={DATA}
keyExtractor={(item) => item.id}
initialFocusedIndex={0}
onEnterPress={handleItemPress}
renderItem={({ item, isFocused }) => (
<TouchableOpacity
style={[styles.item, isFocused && styles.focusedItem]}
accessible={true}
accessibilityState={{ selected: isFocused }}
>
<Text style={[styles.text, isFocused && styles.focusedText]}>
{item.title}
</Text>
</TouchableOpacity>
)}
/>
);
}
const styles = StyleSheet.create({
item: { padding: 16, backgroundColor: 'white' },
focusedItem: { backgroundColor: '#007AFF' },
text: { fontSize: 18, color: '#333' },
focusedText: { color: 'white', fontWeight: 'bold' },
});2D Grid Layout (TV / Dashboard)
Set numColumns to navigate multi-column grids smoothly with Arrow keys / D-Pad:
<KeyboardFlatList
data={DATA}
numColumns={3}
loop={true}
onFocusIndexChange={(index, item) => console.log('Focused:', item.title)}
renderItem={({ item, isFocused }) => (
// Your grid item UI
)}
/>API Reference
<KeyboardFlatList> Props
Inherits all standard FlatListProps.
| Prop | Type | Default | Description |
|---|---|---|---|
| data | ItemT[] | Required | Array of items to render. |
| renderItem | ({ item: ItemT, index: number, isFocused: boolean }) => ReactElement | Required | Renders each item in the list with isFocused status. |
| initialFocusedIndex | number | 0 | Index to highlight when the list first mounts. |
| numColumns | number | 1 | Number of grid columns for 2D layout navigation. |
| loop | boolean | false | When true, navigating past list boundaries loops around. |
| enabled | boolean | true | Set to false to pause key interception (e.g. when a modal is open). |
| onEnterPress | (item: ItemT, index: number) => void | undefined | Callback fired when Enter / D-Pad select is pressed. |
| onFocusIndexChange | (index: number, item: ItemT) => void | undefined | Callback fired whenever the focused item changes. |
License
MIT
