Description:
React Native Keyboard Composer is a native keyboard-aware composer library that handles input interactions for chat applications. It solves keyboard positioning problems through native implementations on both iOS and Android.
Chat interfaces require precise coordination between keyboard animations, scroll position, and input height changes. This library manages those interactions at the native level. The composer responds to keyboard events in real time and maintains proper spacing between messages and input fields.
You can integrate this solution into messaging apps, AI chat interfaces, or any application where text input needs to coordinate with keyboard behavior.
Features
- π¬ Chat-Optimized Layout: Content reacts to keyboard state changes and maintains proper message positioning throughout typing sessions.
- π Intelligent Content Adjustment: The system determines when to push content upward versus when to overlay the keyboard based on scroll position and input state.
- β¨οΈ Auto-Expanding Input: Text input grows vertically as users type multiple lines and shrinks back when content is removed.
- π Scroll Control Button: A scroll-to-bottom button appears automatically when users navigate away from the latest messages.
- π± Cross-Platform Consistency: iOS and Android receive the same keyboard interaction patterns through platform-specific native code.
- ποΈ Stream Control Integration: Built-in stop button appears during AI streaming responses and disappears when streams complete.
- π Theme Adaptation: The interface switches between light and dark modes based on system preferences.
- π Gesture Recognition: iOS users can swipe down to dismiss the keyboard or swipe up to focus and open it.
Use Cases
- AI Chat Applications: Developers building ChatGPT-style interfaces need reliable keyboard handling during streaming responses and multi-line input scenarios.
- Messaging Platforms: Teams creating social messaging apps require consistent keyboard behavior across iOS and Android with proper content positioning.
- Customer Support Chat: Support applications benefit from auto-growing input fields and scroll controls when agents handle multiple conversations simultaneously.
- Collaborative Chat Tools: Development teams building workspace chat features need native keyboard animations that feel smooth during rapid conversation exchanges.
How to Use It
1. Install the package through your preferred package manager.
pnpm add @launchhq/react-native-keyboard-composernpm install @launchhq/react-native-keyboard-composeryarn add @launchhq/react-native-keyboard-composerExpo managed projects require an additional prebuild step to link native modules:
npx expo prebuild2. Import the required components and set up the state for composer height tracking:
import { useState } from 'react';
import { View, ScrollView, StyleSheet } from 'react-native';
import {
KeyboardComposer,
KeyboardAwareWrapper,
} from '@launchhq/react-native-keyboard-composer';
function ChatScreen() {
const [composerHeight, setComposerHeight] = useState(48);
const [messages, setMessages] = useState([]);
const handleSend = (text) => {
setMessages([...messages, { text, timestamp: Date.now() }]);
};
return (
<KeyboardAwareWrapper
style={{ flex: 1 }}
extraBottomInset={composerHeight}
>
<ScrollView contentContainerStyle={styles.scrollContent}>
{messages.map((msg, index) => (
<View key={index} style={styles.message}>
<Text>{msg.text}</Text>
</View>
))}
</ScrollView>
<View style={styles.composerContainer}>
<KeyboardComposer
placeholder="Type a message..."
onSend={handleSend}
onHeightChange={setComposerHeight}
/>
</View>
</KeyboardAwareWrapper>
);
}
const styles = StyleSheet.create({
scrollContent: {
padding: 16,
},
message: {
backgroundColor: '#f0f0f0',
padding: 12,
borderRadius: 8,
marginBottom: 8,
},
composerContainer: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
paddingHorizontal: 16,
paddingBottom: 16,
},
});The KeyboardAwareWrapper accepts an extraBottomInset prop that tells it how much space the composer occupies. Update this value whenever the composer height changes. The wrapper component adjusts scroll content position automatically during keyboard animations.
4. Track streaming state and pass it to the composer to show stop controls:
import { useState } from 'react';
import { KeyboardComposer } from '@launchhq/react-native-keyboard-composer';
function AIChat() {
const [isStreaming, setIsStreaming] = useState(false);
const [streamController, setStreamController] = useState(null);
const handleSend = async (text) => {
setIsStreaming(true);
const controller = new AbortController();
setStreamController(controller);
try {
await fetchAIStream(text, {
signal: controller.signal,
onChunk: (chunk) => {
// Process streaming chunks
}
});
} catch (error) {
if (error.name !== 'AbortError') {
console.error('Stream error:', error);
}
} finally {
setIsStreaming(false);
setStreamController(null);
}
};
const handleStop = () => {
if (streamController) {
streamController.abort();
}
};
return (
<KeyboardComposer
placeholder="Ask anything..."
isStreaming={isStreaming}
onSend={handleSend}
onStop={handleStop}
/>
);
}The composer displays a stop button when isStreaming is true. Users can interrupt long responses by tapping the stop button, which triggers the onStop callback.
5. Control keyboard visibility through state changes:
import { useState } from 'react';
import { Button } from 'react-native';
import { KeyboardComposer } from '@launchhq/react-native-keyboard-composer';
function ControlledInput() {
const [blurTrigger, setBlurTrigger] = useState(0);
const dismissKeyboard = () => {
setBlurTrigger(Date.now());
};
return (
<>
<Button title="Close Keyboard" onPress={dismissKeyboard} />
<KeyboardComposer
blurTrigger={blurTrigger}
placeholder="Type here..."
onSend={(text) => console.log(text)}
/>
</>
);
}Change the blurTrigger value to any new number or timestamp. The composer detects the change and dismisses the keyboard immediately.
6. Apply custom styles to match your design system:
import { StyleSheet } from 'react-native';
import { KeyboardComposer } from '@launchhq/react-native-keyboard-composer';
function StyledComposer() {
return (
<View style={styles.container}>
<View style={styles.wrapper}>
<KeyboardComposer
placeholder="Message..."
minHeight={56}
maxHeight={140}
style={styles.composer}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
paddingHorizontal: 20,
paddingBottom: 20,
},
wrapper: {
borderRadius: 28,
backgroundColor: '#F2F2F7',
overflow: 'hidden',
borderWidth: 1,
borderColor: '#E5E5EA',
},
composer: {
paddingHorizontal: 4,
},
});The composer accepts standard React Native view styles through the style prop. Wrap the composer in additional views to create borders, shadows, or background effects.
API Reference
KeyboardComposer Props
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | “Type a message⦔ | Text shown when input is empty |
minHeight | number | 48 | Minimum composer height in points or density-independent pixels |
maxHeight | number | 120 | Maximum height before internal scrolling begins |
sendButtonEnabled | boolean | true | Controls whether send button responds to taps |
editable | boolean | true | Determines if text can be entered or modified |
autoFocus | boolean | false | Focuses input and opens keyboard on component mount |
blurTrigger | number | undefined | Change this value to dismiss keyboard programmatically |
isStreaming | boolean | false | Shows stop button instead of send button when true |
onChangeText | (text: string) => void | undefined | Fires whenever text content changes |
onSend | (text: string) => void | undefined | Fires when user taps send button |
onStop | () => void | undefined | Fires when user taps stop button during streaming |
onHeightChange | (height: number) => void | undefined | Fires when composer height changes due to text growth |
onKeyboardHeightChange | (height: number) => void | undefined | Fires when keyboard height changes during animations |
onComposerFocus | () => void | undefined | Fires when input receives focus |
onComposerBlur | () => void | undefined | Fires when input loses focus |
style | StyleProp | undefined | Custom styles applied to composer container |
KeyboardAwareWrapper Props
| Prop | Type | Default | Description |
|---|---|---|---|
extraBottomInset | number | 0 | Additional bottom space reserved for composer (typically composer height) |
scrollToTopTrigger | number | 0 | Change this value to scroll new content into view at top of scroll area |
style | StyleProp | undefined | Custom styles applied to wrapper container |
children | ReactNode | undefined | Should contain a ScrollView or FlatList component |
Constants
Access default values and spacing constants:
import { constants } from '@launchhq/react-native-keyboard-composer';
const {
defaultMinHeight, // 48
defaultMaxHeight, // 120
contentGap, // 32
} = constants;The contentGap constant represents the space maintained between the last message and the composer. Both platforms use identical numerical values, though visual spacing may differ due to platform-specific safe area handling.
Related Resources
- React Native Keyboard Controller: A library that synchronizes keyboard animations with scroll views and handles keyboard state management across React Native applications.
- React Native Gifted Chat: A complete chat UI implementation that includes message bubbles, avatars, typing indicators, and customizable themes for messaging applications.
- React Native RNGH: Gesture handling library that processes touch interactions and gestures at native level for smooth animations and responsive controls.
- React Native Reanimated: Animation library that runs animations on native threads for smooth 60fps performance during keyboard transitions and UI state changes.
FAQs
Q: How do I add extra spacing between messages and the composer?
A: Add paddingBottom to your ScrollView’s contentContainerStyle prop. The library maintains a base gap of 24 points, and additional padding stacks on top of this value.
Q: Can I customize the send button icon?
A: The current version includes a default send button. Future releases will add props for custom buttons and icons. Track updates on the GitHub repository for this feature.
Q: Why does content jump when the keyboard closes?
A: The wrapper needs the correct extraBottomInset value. Pass the composer height from onHeightChange to the wrapper’s extraBottomInset prop. The wrapper uses this value to calculate proper scroll adjustments.
Q: Does the library support React Native Web?
A: No. The library depends on native keyboard APIs that do not exist in web browsers. Use this library only for iOS and Android applications.