In React Native, how does KeyboardAvoidingView keep a chat composer above the keyboard, and what do behavior and keyboardVerticalOffset do?
answer
- measures itself, watches the keyboard
- padding, height or position
- no behavior means no effect
- parent-relative frame vs screen keyboard
- offset = what sits above the view
basics
~20 sKeyboardAvoidingView measures its frame, listens for keyboard events and shifts its content by the overlap, using behavior padding, height or position. Without behavior it does nothing. keyboardVerticalOffset adds the distance from the top of the screen to the view, such as a header.
solid answer
~40 s`KeyboardAvoidingView` measures itself with `onLayout`, subscribes to keyboard events (`keyboardWillShow`/`WillHide` on iOS, `keyboardDidShow`/`DidHide` on Android) and computes how far the keyboard overlaps its bottom edge. `behavior` decides how that overlap is applied: `'padding'` adds bottom padding, `'height'` shrinks the view's height, and `'position'` offsets an inner container styled by `contentContainerStyle`. There is no default: without `behavior` it renders a plain `View` and never moves. Because its frame is relative to its parent while the keyboard reports screen coordinates, a screen below a header underestimates the overlap by the header's height. `keyboardVerticalOffset` supplies that distance. A common setup is `'padding'` on iOS and `'height'` on Android, with the offset set to the header's height, verified on devices.
code
tsx · 24 linesimport type {ReactNode} from 'react';
import {KeyboardAvoidingView, Platform, StyleSheet, TextInput, View} from 'react-native';
type ChatScreenProps = {
headerHeight: number;
messages: ReactNode;
};
export function ChatScreen({headerHeight, messages}: ChatScreenProps) {
return (
<KeyboardAvoidingView
style={styles.flex}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={headerHeight}>
<View style={styles.flex}>{messages}</View>
<TextInput style={styles.composer} placeholder="Message" multiline />
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
flex: {flex: 1},
composer: {minHeight: 44, paddingHorizontal: 12, borderTopWidth: 1, borderColor: '#dddddd'},
});go deeper
Recall that KeyboardAvoidingView must get a behavior, padding, height or position, and that it wraps the screen whose content must move above the keyboard.
Explain the overlap calculation: a parent-relative frame against the keyboard's screen position, why a header requires keyboardVerticalOffset, and which events it uses on each platform.
Diagnose composers hidden by exactly the header height, choose behavior per platform after testing on devices, and remember that safe-area padding is not removed when the keyboard opens.
Decide whether core KeyboardAvoidingView is enough for the app's input-heavy screens or whether a shared keyboard-handling layer is worth owning, and make that one pattern everyone uses.
## The problem On a phone the software keyboard slides up over the bottom third of the screen. A chat composer pinned to the bottom of the screen is exactly where the keyboard lands, so without help the user types into a field they cannot see. React Native's answer in core is **`KeyboardAvoidingView`** (from `react-native`): a `View` that listens for the keyboard and changes its own layout so its content ends above it. ## How it works `KeyboardAvoidingView` does three things: 1. **Measures itself** with `onLayout`, which reports its frame relative to its **parent**. 2. **Listens for the keyboard.** On iOS it subscribes to `keyboardWillShow` and `keyboardWillHide`, so it can animate together with the keyboard, using a layout animation with the keyboard's own duration. On Android it uses `keyboardDidShow` and `keyboardDidHide`, the only keyboard events Android provides. 3. **Computes the overlap**: the bottom of its frame minus the keyboard's top edge (`screenY`), after subtracting `keyboardVerticalOffset`. It then applies that overlap according to `behavior`. ## The behavior prop | `behavior` | What changes when the keyboard opens | |---|---| | `'padding'` | adds `paddingBottom` equal to the overlap, so children are pushed up inside the view | | `'height'` | sets an explicit `height` (its original height minus the overlap) and turns off `flex` while the keyboard is up | | `'position'` | wraps children in an inner `View` whose `bottom` is set to the overlap; style that wrapper with `contentContainerStyle` | | not set | **nothing**: it renders a plain `View` and never adjusts | There is **no default behaviour**. The docs say that iOS and Android interact with the prop differently and recommend setting it on both. A common starting point is `'padding'` on iOS and `'height'` on Android, chosen with `Platform.OS` and then verified on real devices. On Android the window itself may already resize for the keyboard, depending on how the app's activity is configured. `enabled` (default `true`) switches the adjustment off without unmounting the view. ## keyboardVerticalOffset: why screens with headers break The subtle part is the coordinate systems. The keyboard's position (`screenY`) is in **screen** coordinates, but the frame from `onLayout` is relative to the **parent**. If the `KeyboardAvoidingView` fills a screen that starts below a navigation header, its frame says `y = 0` while its real top is the header's height further down. The computed overlap is then too small by exactly that height, and the composer stays partly hidden. `keyboardVerticalOffset` (default `0`) corrects this. The docs describe it as "the distance between the top of the user screen and the react native view". Set it to the height of whatever sits above the view, such as the header, including the status-bar area if the header covers it. ## A chat composer, step by step - Make the `KeyboardAvoidingView` the screen's root with `flex: 1`. - Put the message list in a `flex: 1` child and the composer below it. - Choose `behavior` per platform. - Set `keyboardVerticalOffset` to the header's height. - Test with the header shown and hidden, in portrait and landscape, on both platforms. ## Common mistakes - **Leaving `behavior` unset** and concluding that the component "doesn't work". It never adjusts without it. - **Using `keyboardVerticalOffset` as spacing.** It is a coordinate correction for what sits above the view, not a margin between input and keyboard. Add spacing with ordinary padding. - **Hard-coding the offset** from one device. Header heights change with platform, orientation and header options. - **Wrapping only the composer** in `KeyboardAvoidingView`. The view must span the area that has to shrink or shift, usually the whole screen body, or its overlap calculation has nothing to move. - **Expecting identical motion on both platforms.** iOS animates with the keyboard's own timing; on Android, where the event duration is always zero, the adjustment appears once the keyboard is up. ## Things it does not do - It does not scroll a `ScrollView` to the focused input. That is a scroll-container concern. - It does not know about safe-area insets. Bottom padding you add for the home indicator stays in place when the keyboard opens. - A `KeyboardAvoidingView` nested deep inside a layout is harder to reason about. Keep it at the root of the screen whose content must move.
- Why does React Native's KeyboardAvoidingView use keyboardWillShow on iOS but keyboardDidShow on Android?iOS sends will-events before the keyboard moves, with its duration, so the view can animate in step with it. Android only emits `keyboardDidShow` and `keyboardDidHide`, so the adjustment happens once the keyboard is already up. The source also notes that iOS's will-hide and will-show handle undocked, split and floating keyboards better than frame-change events.
- What changes when KeyboardAvoidingView uses behavior='position'?Instead of changing its own padding or height, it renders an inner `View` around the children and sets that wrapper's `bottom` to the overlap, moving the content up as a block. Style the wrapper through `contentContainerStyle`. The outer view keeps its size, so content can move over whatever is above it.
saying these in an interview costs you the question
- KeyboardAvoidingView defaults to behavior 'padding', so the prop is optional.
- keyboardVerticalOffset is the extra gap you want between the input and the keyboard.
- iOS and Android handle every behavior value identically.
- KeyboardAvoidingView also scrolls a ScrollView to the focused input.
- KeyboardAvoidingView automatically subtracts the header height of the screen.