Skip to content

Commit 7ece2d8

Browse files
authored
docs: KeyboardChatScrollView fixes after devs feedback (#1322)
## 📜 Description Updated documentation after reviewing own changes and gathering feedback from developers. ## 💡 Motivation and Context Current documentation is good, but lacks few important aspects (such as enabling reanimated feature flags). To avoid spamming with new issues and improve dev experience I added more content. ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### Docs - added troubleshooting section with enabling reanimated feature flag; - strict typing of `ref` from `VirtualizedScrollView`; - make video default size so content is not jumping while page is laoding - add video to "building chat app" page. ## 🤔 How Has This Been Tested? Tested via preview and locally on `localhost:3000`. ## 📸 Screenshots (if appropriate): <img width="1350" height="1157" alt="image" src="https://github.com/user-attachments/assets/0d8f4625-18ee-40c3-a38f-2bc8c78f636a" /> ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
1 parent 11c0dbf commit 7ece2d8

2 files changed

Lines changed: 97 additions & 23 deletions

File tree

docs/docs/api/components/keyboard-chat-scroll-view.mdx

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
import Video from "@site/src/components/Video";
66

7-
<Video src="/video/keyboard-chat-scroll-view/always.mov" width={35} />
7+
<Video
8+
src="/video/keyboard-chat-scroll-view/always.mov"
9+
style={{ height: "40vh" }}
10+
/>
811

912
## Props
1013

@@ -43,25 +46,37 @@ Controls how the chat content responds when the keyboard appears. Defaults to `"
4346

4447
Content always lifts with the keyboard, keeping the bottom messages visible **regardless** of the current scroll position. This is the most common chat app behavior, used by **Telegram**, **WhatsApp**, and others.
4548

46-
<Video src="/video/keyboard-chat-scroll-view/always.mov" width={25} />
49+
<Video
50+
src="/video/keyboard-chat-scroll-view/always.mov"
51+
style={{ height: "40vh" }}
52+
/>
4753

4854
#### `whenAtEnd`
4955

5056
Content lifts only when the scroll view is **at the end** (i.e., the last message is visible or near the bottom). If the user has scrolled up to read older messages, the keyboard won't push the content around. This matches the **ChatGPT** mobile app behavior.
5157

52-
<Video src="/video/keyboard-chat-scroll-view/when-at-end.mov" width={25} />
58+
<Video
59+
src="/video/keyboard-chat-scroll-view/when-at-end.mov"
60+
style={{ height: "40vh" }}
61+
/>
5362

5463
#### `persistent`
5564

5665
Content lifts when the keyboard appears, but **does not drop back** when the keyboard hides. The scroll position stays where it was pushed to. This matches the **Claude** mobile app behavior.
5766

58-
<Video src="/video/keyboard-chat-scroll-view/persistent.mp4" width={25} />
67+
<Video
68+
src="/video/keyboard-chat-scroll-view/persistent.mp4"
69+
style={{ height: "40vh" }}
70+
/>
5971

6072
#### `never`
6173

6274
Content never moves in response to the keyboard. The keyboard simply overlaps the chat. This matches the **Perplexity** app behavior.
6375

64-
<Video src="/video/keyboard-chat-scroll-view/never.mov" width={25} />
76+
<Video
77+
src="/video/keyboard-chat-scroll-view/never.mov"
78+
style={{ height: "40vh" }}
79+
/>
6580

6681
### `offset`
6782

@@ -76,12 +91,18 @@ This is useful when the input is not at the very bottom of the screen — for ex
7691
First, create a wrapper component:
7792

7893
```tsx title="VirtualizedListScrollView.tsx"
79-
import { forwardRef } from "react";
94+
import React, { forwardRef } from "react";
8095
import { KeyboardChatScrollView } from "react-native-keyboard-controller";
8196

8297
import type { ScrollViewProps } from "react-native";
98+
import type { KeyboardChatScrollViewProps } from "react-native-keyboard-controller";
99+
100+
type Ref = React.ElementRef<typeof KeyboardChatScrollView>;
83101

84-
const VirtualizedListScrollView = forwardRef((props: ScrollViewProps, ref) => {
102+
const VirtualizedListScrollView = forwardRef<
103+
Ref,
104+
ScrollViewProps & KeyboardChatScrollViewProps
105+
>((props, ref) => {
85106
return (
86107
<KeyboardChatScrollView
87108
ref={ref}
@@ -180,3 +201,29 @@ On iOS we change the [`contentOffset`](https://reactnative.dev/docs/scrollview#c
180201
#### Android
181202

182203
On Android we adjust the scroll position inside the [`onMove`](../hooks/keyboard/use-keyboard-handler#onmove) handler via the [`scrollTo`](https://docs.swmansion.com/react-native-reanimated/docs/scroll/scrollTo/) method on the UI thread from a worklet.
204+
205+
## Troubleshooting
206+
207+
### Reanimated feature flag
208+
209+
`KeyboardChatScrollView` relies on a Reanimated commit hook internally. If you're using **Reanimated < 4.3.0**, you need to enable the [`USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS`](https://docs.swmansion.com/react-native-reanimated/docs/guides/feature-flags/#use_commit_hook_only_for_react_commits) feature flag in your `package.json`:
210+
211+
```json
212+
{
213+
"reanimated": {
214+
"staticFeatureFlags": {
215+
"USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS": true
216+
}
217+
}
218+
}
219+
```
220+
221+
After adding this, run `pod install` (iOS) and rebuild the app.
222+
223+
:::tip Reanimated 4.3.0+ relevance
224+
If you're on **Reanimated 4.3.0+**, this flag is enabled by default — no extra configuration needed.
225+
:::
226+
227+
:::info What it affects?
228+
If you don't enable this flag you'll see de-synchronized keyboard animation on Android/Fabric architecture.
229+
:::

docs/docs/guides/building-chat-app.mdx

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ keywords:
1515

1616
Keyboard handling in chat applications has always been one of the trickiest problems in mobile development — even on native platforms. Chat apps push keyboard interactions to their limits: interactive dismissal, content repositioning, smooth transitions between the keyboard and custom input views, and all of it at 120 FPS. Getting this right requires deep integration between the keyboard, scroll views, and layout systems — far more than a general-purpose component can offer.
1717

18+
import Video from "@site/src/components/Video";
19+
20+
<Video
21+
src="/video/keyboard-chat-scroll-view/always.mov"
22+
style={{ height: "40vh", marginBottom: 20 }}
23+
/>
24+
1825
## Why general-purpose components fall short
1926

2027
You might be tempted to reach for `KeyboardAvoidingView` or `KeyboardAwareScrollView` to handle keyboard interactions in a chat app. While these components work well for forms, settings screens, and other straightforward layouts, they weren't designed for the unique demands of a chat interface.
@@ -199,15 +206,21 @@ For production chat apps you'll likely use a virtualized list (`FlatList`, `Flas
199206
Create a wrapper that passes `KeyboardChatScrollView` props down:
200207

201208
```tsx title="VirtualizedListScrollView.tsx"
202-
import { forwardRef } from "react";
209+
import React, { forwardRef } from "react";
203210
import { KeyboardChatScrollView } from "react-native-keyboard-controller";
204211
import { useSafeAreaInsets } from "react-native-safe-area-context";
205212

206213
import type { ScrollViewProps } from "react-native";
214+
import type { KeyboardChatScrollViewProps } from "react-native-keyboard-controller";
215+
216+
type Ref = React.ElementRef<typeof KeyboardChatScrollView>;
207217

208218
const BOTTOM_OFFSET = 8; // distance from safe area to input
209219

210-
const VirtualizedListScrollView = forwardRef((props: ScrollViewProps, ref) => {
220+
const VirtualizedListScrollView = forwardRef<
221+
Ref,
222+
ScrollViewProps & KeyboardChatScrollViewProps
223+
>((props, ref) => {
211224
const { bottom } = useSafeAreaInsets();
212225

213226
return (
@@ -272,26 +285,27 @@ const renderScrollComponent = useCallback(
272285
If your list uses the `inverted` prop (the standard pattern for chat lists where newest messages appear at the bottom), make sure to pass `inverted` to `KeyboardChatScrollView` as well:
273286

274287
```tsx title="VirtualizedListScrollView.tsx"
275-
const VirtualizedListScrollView = forwardRef(
276-
({ inverted, ...props }: ScrollViewProps & { inverted?: boolean }, ref) => {
277-
return (
278-
<KeyboardChatScrollView
279-
ref={ref}
280-
// add-new-code
281-
inverted={inverted}
282-
{...props}
283-
/>
284-
);
285-
},
286-
);
288+
const VirtualizedListScrollView = forwardRef<
289+
Ref,
290+
ScrollViewProps & KeyboardChatScrollViewProps
291+
>(({ inverted, ...props }, ref) => {
292+
return (
293+
<KeyboardChatScrollView
294+
ref={ref}
295+
// add-new-code
296+
inverted={inverted}
297+
{...props}
298+
/>
299+
);
300+
});
287301
```
288302

289303
## Complete example
290304

291305
Here is a complete chat screen that ties together all the pieces — `KeyboardChatScrollView` with a `FlatList`, interactive dismissal, sticky input, and safe area handling:
292306

293307
```tsx
294-
import { useCallback, useRef, useState } from "react";
308+
import React, { forwardRef, useCallback, useRef, useState } from "react";
295309
import {
296310
FlatList,
297311
StyleSheet,
@@ -310,11 +324,18 @@ import {
310324
useSafeAreaInsets,
311325
} from "react-native-safe-area-context";
312326

327+
import type { KeyboardChatScrollViewProps } from "react-native-keyboard-controller";
328+
329+
type Ref = React.ElementRef<typeof KeyboardChatScrollView>;
330+
313331
const MARGIN = 8;
314332
const INPUT_HEIGHT = 42;
315333

316334
// Wrapper for virtualized lists
317-
const ChatScrollView = forwardRef((props: ScrollViewProps, ref) => {
335+
const ChatScrollView = forwardRef<
336+
Ref,
337+
ScrollViewProps & KeyboardChatScrollViewProps
338+
>((props, ref) => {
318339
const { bottom } = useSafeAreaInsets();
319340

320341
return (
@@ -411,3 +432,9 @@ Or play with the code in live mode directly in the browser:
411432
## API reference
412433

413434
For the full list of props and design principles, see the [`KeyboardChatScrollView` API reference](../api/components/keyboard-chat-scroll-view).
435+
436+
## Troubleshooting
437+
438+
:::danger Check troubleshooting section first
439+
If you encounter any issues with `KeyboardChatScrollView`, please check the [Troubleshooting section](../api/components/keyboard-chat-scroll-view#troubleshooting) first before reporting a bug. If you're still having trouble, feel free to [open an issue](https://github.com/kirillzyusko/react-native-keyboard-controller/issues/new) on GitHub.
440+
:::

0 commit comments

Comments
 (0)