A React Native ScrollView component that resizes when the keyboard appears.
—
The KeyboardAwareSectionList is a SectionList component that automatically handles keyboard appearance by scrolling to keep focused TextInput fields visible. It extends React Native's SectionList with keyboard awareness capabilities, making it ideal for sectioned lists containing input fields.
A SectionList component enhanced with keyboard awareness functionality.
/**
* A SectionList component that automatically scrolls to keep focused TextInput fields visible
* when the keyboard appears. Extends SectionList with keyboard-aware behavior.
*/
export class KeyboardAwareSectionList<ItemT = any> extends React.Component<
KeyboardAwareSectionListProps<ItemT>,
KeyboardAwareState
> {
getScrollResponder(): any;
scrollToPosition(x: number, y: number, animated?: boolean): void;
scrollToEnd(animated?: boolean): void;
scrollForExtraHeightOnAndroid(extraHeight: number): void;
scrollToFocusedInput(
reactNode: any,
extraHeight?: number,
keyboardOpeningTime?: number
): void;
scrollIntoView(
element: React.ReactElement,
options?: ScrollIntoViewOptions
): Promise<void>;
update(): void;
}
interface KeyboardAwareSectionListProps<ItemT> extends KeyboardAwareProps, SectionListProps<ItemT> {}Usage Examples:
import React, { useState } from 'react';
import { View, TextInput, Text, StyleSheet } from 'react-native';
import { KeyboardAwareSectionList } from 'react-native-keyboard-aware-scroll-view';
interface ContactSection {
title: string;
data: Contact[];
}
interface Contact {
id: string;
name: string;
email: string;
phone: string;
}
// Basic usage with sectioned contact form
export function ContactForm() {
const [sections] = useState<ContactSection[]>([
{
title: 'Personal Contacts',
data: [
{ id: '1', name: '', email: '', phone: '' },
{ id: '2', name: '', email: '', phone: '' },
]
},
{
title: 'Work Contacts',
data: [
{ id: '3', name: '', email: '', phone: '' },
{ id: '4', name: '', email: '', phone: '' },
]
},
{
title: 'Emergency Contacts',
data: [
{ id: '5', name: '', email: '', phone: '' },
]
}
]);
const renderContactItem = ({ item }: { item: Contact }) => (
<View style={styles.contactItem}>
<TextInput
style={styles.input}
placeholder="Name"
defaultValue={item.name}
/>
<TextInput
style={styles.input}
placeholder="Email"
defaultValue={item.email}
keyboardType="email-address"
/>
<TextInput
style={styles.input}
placeholder="Phone"
defaultValue={item.phone}
keyboardType="phone-pad"
/>
</View>
);
const renderSectionHeader = ({ section }: { section: ContactSection }) => (
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>{section.title}</Text>
</View>
);
return (
<KeyboardAwareSectionList
sections={sections}
renderItem={renderContactItem}
renderSectionHeader={renderSectionHeader}
keyExtractor={item => item.id}
style={styles.container}
enableOnAndroid={true}
extraHeight={75}
/>
);
}
// Advanced usage with mixed content types
export function SettingsForm() {
const [settingsSections] = useState([
{
title: 'Account Settings',
data: [
{ id: 'username', type: 'input', label: 'Username', value: '' },
{ id: 'email', type: 'input', label: 'Email', value: '' },
{ id: 'bio', type: 'textarea', label: 'Bio', value: '' },
]
},
{
title: 'Preferences',
data: [
{ id: 'theme', type: 'input', label: 'Theme Color', value: '' },
{ id: 'language', type: 'input', label: 'Language', value: '' },
]
}
]);
const renderSettingItem = ({ item }: { item: any }) => (
<View style={styles.settingItem}>
<Text style={styles.settingLabel}>{item.label}</Text>
{item.type === 'textarea' ? (
<TextInput
style={[styles.input, styles.textarea]}
placeholder={`Enter ${item.label.toLowerCase()}`}
defaultValue={item.value}
multiline
numberOfLines={3}
/>
) : (
<TextInput
style={styles.input}
placeholder={`Enter ${item.label.toLowerCase()}`}
defaultValue={item.value}
/>
)}
</View>
);
const renderSectionHeader = ({ section }: { section: any }) => (
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>{section.title}</Text>
</View>
);
return (
<KeyboardAwareSectionList
sections={settingsSections}
renderItem={renderSettingItem}
renderSectionHeader={renderSectionHeader}
keyExtractor={item => item.id}
style={styles.container}
enableOnAndroid={true}
enableAutomaticScroll={true}
extraHeight={100}
extraScrollHeight={50}
keyboardOpeningTime={250}
resetScrollToCoords={{ x: 0, y: 0 }}
enableResetScrollToCoords={true}
stickySectionHeadersEnabled={true}
onKeyboardWillShow={(frames) => console.log('Keyboard will show', frames)}
/>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#f5f5f5' },
sectionHeader: {
backgroundColor: '#e0e0e0',
padding: 15,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
},
sectionTitle: {
fontSize: 16,
fontWeight: 'bold',
color: '#333',
},
contactItem: {
backgroundColor: 'white',
padding: 15,
borderBottomWidth: 1,
borderBottomColor: '#eee',
},
settingItem: {
backgroundColor: 'white',
padding: 15,
borderBottomWidth: 1,
borderBottomColor: '#eee',
},
settingLabel: {
fontSize: 14,
fontWeight: '500',
marginBottom: 8,
color: '#333',
},
input: {
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
marginBottom: 10,
borderRadius: 5,
backgroundColor: '#fafafa',
},
textarea: {
height: 80,
textAlignVertical: 'top',
},
});Gets the underlying SectionList's scroll responder for advanced scroll operations.
/**
* Get the underlying SectionList's scroll responder
* @returns The scroll responder instance
*/
getScrollResponder(): any;Programmatically scrolls to a specific position in the SectionList.
/**
* Scroll to specific position with or without animation
* @param x - The x coordinate to scroll to
* @param y - The y coordinate to scroll to
* @param animated - Whether to animate the scroll (default: true)
*/
scrollToPosition(x: number, y: number, animated?: boolean): void;Scrolls to the end of the SectionList content.
/**
* Scroll to end with or without animation
* @param animated - Whether to animate the scroll (default: true)
*/
scrollToEnd(animated?: boolean): void;Usage Example:
import React, { useRef } from 'react';
import { Button } from 'react-native';
import { KeyboardAwareSectionList } from 'react-native-keyboard-aware-scroll-view';
export function ScrollableSectionList({ sections }: { sections: any[] }) {
const sectionListRef = useRef<KeyboardAwareSectionList>(null);
const scrollToTop = () => {
sectionListRef.current?.scrollToPosition(0, 0, true);
};
const scrollToEnd = () => {
sectionListRef.current?.scrollToEnd(true);
};
return (
<>
<KeyboardAwareSectionList
ref={sectionListRef}
sections={sections}
renderItem={({ item }) => <YourItemComponent item={item} />}
renderSectionHeader={({ section }) => <YourHeaderComponent section={section} />}
keyExtractor={item => item.id}
/>
<Button title="Scroll to Top" onPress={scrollToTop} />
<Button title="Scroll to End" onPress={scrollToEnd} />
</>
);
}Android-specific method for scrolling with additional height offset.
/**
* Android-specific scroll method with extra height offset (Android only)
* @param extraHeight - Additional height to add to the scroll offset
*/
scrollForExtraHeightOnAndroid(extraHeight: number): void;Scrolls to a specific focused TextInput field within a section item.
/**
* Scroll to a specific focused input field
* @param reactNode - The React node handle of the input to scroll to
* @param extraHeight - Additional height offset (optional)
* @param keyboardOpeningTime - Custom keyboard opening delay (optional)
*/
scrollToFocusedInput(
reactNode: any,
extraHeight?: number,
keyboardOpeningTime?: number
): void;Scrolls a React element into view with customizable positioning.
/**
* Scrolls an element into view with customizable positioning
* @param element - The React element to scroll into view
* @param options - Configuration options for scroll positioning
* @returns Promise that resolves when scrolling is complete
*/
scrollIntoView(
element: React.ReactElement,
options?: ScrollIntoViewOptions
): Promise<void>;Manually triggers scrolling to the currently focused input field.
/**
* Manually trigger scroll to currently focused input
* Useful for updating scroll position after layout changes
*/
update(): void;The KeyboardAwareSectionList accepts all standard SectionList props plus the KeyboardAwareProps interface:
interface KeyboardAwareSectionListProps<ItemT> extends KeyboardAwareProps, SectionListProps<ItemT> {
// Inherits all SectionList props (sections, renderItem, renderSectionHeader, etc.)
// Plus all KeyboardAwareProps (see main documentation)
}import React, { useState } from 'react';
import { View, TextInput, Text } from 'react-native';
import { KeyboardAwareSectionList } from 'react-native-keyboard-aware-scroll-view';
export function UserProfileSections() {
const [profileSections] = useState([
{
title: 'Basic Information',
data: [
{ id: 'firstName', label: 'First Name', value: '' },
{ id: 'lastName', label: 'Last Name', value: '' },
{ id: 'email', label: 'Email', value: '' },
]
},
{
title: 'Contact Details',
data: [
{ id: 'phone', label: 'Phone Number', value: '' },
{ id: 'address', label: 'Address', value: '' },
{ id: 'city', label: 'City', value: '' },
]
},
{
title: 'Additional Info',
data: [
{ id: 'bio', label: 'Bio', value: '', multiline: true },
{ id: 'website', label: 'Website', value: '' },
]
}
]);
const renderProfileItem = ({ item }: { item: any }) => (
<View style={{ padding: 15, backgroundColor: 'white' }}>
<Text style={{ marginBottom: 8, fontWeight: '500' }}>{item.label}</Text>
<TextInput
style={{
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
borderRadius: 5,
height: item.multiline ? 80 : 40,
}}
placeholder={`Enter ${item.label.toLowerCase()}`}
defaultValue={item.value}
multiline={item.multiline}
textAlignVertical={item.multiline ? 'top' : 'center'}
/>
</View>
);
const renderSectionHeader = ({ section }: { section: any }) => (
<View style={{ backgroundColor: '#f0f0f0', padding: 12 }}>
<Text style={{ fontSize: 16, fontWeight: 'bold' }}>{section.title}</Text>
</View>
);
return (
<KeyboardAwareSectionList
sections={profileSections}
renderItem={renderProfileItem}
renderSectionHeader={renderSectionHeader}
keyExtractor={item => item.id}
enableOnAndroid={true}
extraHeight={100}
stickySectionHeadersEnabled={true}
/>
);
}enableOnAndroid={true} and windowSoftInputMode="adjustPan" in AndroidManifest.xml for full functionalityInstall with Tessl CLI
npx tessl i tessl/npm-react-native-keyboard-aware-scroll-view