fix: strict api compatibility (#1560)
## 📜 Description
Fixed compatibility of
`KeyboardAwareScrollView`/`KeyboardChatScrollView` with
`react-native-strict-api`.
## đź’ˇ Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
<!-- If it fixes an open issue, please link to the issue here. -->
React Native’s `react-native-strict-api` export condition exposes
`ScrollView` as a function component rather than a class. Our existing
ref types relied on class-instance typing:
- `KeyboardAwareScrollViewRef` intersected with `ScrollView`
- `KeyboardChatScrollView` exposed Reanimated’s `AnimatedScrollView` ref
type, which internally relies on the same pattern
Under strict API, those types lose imperative methods such as
`scrollTo`, `scrollToEnd`, and `measure`. The runtime ref is still
valid; this is a TypeScript declaration issue.
This change derives the native `ScrollView` instance type with
`React.ComponentRef<typeof ScrollView>` and exposes it as
`KeyboardChatScrollViewRef`. It keeps the public ref API correct in both
classic and strict-API React Native typings.
Possible alternatives:
- Keep `React.ElementRef<typeof KeyboardChatScrollView>` in consumers:
this works only when the component’s own public ref declaration is
correct. It cannot fix the broken inferred ref type under strict API.
- Type the ref as `ScrollView`: this works with classic React Native
declarations but fails under strict API because `ScrollView` becomes a
component type, not its instance type.
- Expose Reanimated’s `AnimatedScrollView`: this preserves the existing
issue because Reanimated’s type is built on the classic `ScrollView`
class shape.
- Use consumer-side casts or wrapper components: this is a workaround,
but pushes library typing details to every consumer.
- Fix Reanimated’s declarations upstream: worthwhile independently, but
does not remove our responsibility to expose a stable public ref type.
We chose `ComponentRef<typeof ScrollView>` because it resolves to the
actual imperative instance in both typing modes, matches the runtime ref
shape, and provides a simple exported type for consumers:
`useRef<KeyboardChatScrollViewRef>(null)`.
Closes
https://github.com/kirillzyusko/react-native-keyboard-controller/issues/1559
## 📢 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 -->
### JS
- added `KeyboardChatScrollViewRef` (similar to
`KeyboardAwareScrollViewRef`);
- change ref signatures so that they are compatible with both strict and
non-strict API;
### Docs
- use `KeyboardChatScrollViewRef` instead of self derived ref;
## 🤔 How Has This Been Tested?
Tested with following code:
```tsx
import { useRef } from "react";
import {
KeyboardAwareScrollView,
KeyboardChatScrollView,
} from "react-native-keyboard-controller";
import type { KeyboardAwareScrollViewRef } from "react-native-keyboard-controller";
type KeyboardChatScrollViewRef = React.ElementRef<
typeof KeyboardChatScrollView
>;
export function StrictApiReproduction() {
const ref = useRef<KeyboardAwareScrollViewRef>(null);
return (
<KeyboardAwareScrollView
ref={ref}
onLayout={() => {
ref.current?.assureFocusedInputVisible();
ref.current?.scrollTo({ animated: true, y: 0 });
ref.current?.scrollToEnd({ animated: true });
}}
/>
);
}
export function StrictApiKeyboardChatScrollViewReproduction() {
const ref = useRef<KeyboardChatScrollViewRef>(null);
return (
<KeyboardChatScrollView
ref={ref}
onLayout={() => {
ref.current?.scrollTo({ animated: true, y: 0 });
ref.current?.scrollToEnd({ animated: true });
}}
/>
);
}
```
And following `tsconfig.json` in `example`:
```json
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
"customConditions": ["react-native-strict-api", "react-native"]
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["**/node_modules", "**/Pods"]
}
```
## 📸 Screenshots (if appropriate):
### KeyboardAwareScrollView
|Before|After|
|-------|-----|
|<img width="1088" height="373" alt="Screenshot 2026-07-21 at 10 46 32"
src="https://github.com/user-attachments/assets/80fd86e9-d4d2-41cf-a221-54a0d50a87cd"
/>|<img width="726" height="370" alt="Screenshot 2026-07-21 at 10 48 17"
src="https://github.com/user-attachments/assets/73232e16-b9d9-46fa-b265-7cc0a92d7851"
/>|
### KeyboardChatScrollView
|Before|After|
|-------|-----|
|<img width="1323" height="347" alt="Screenshot 2026-07-21 at 11 16 31"
src="https://github.com/user-attachments/assets/de3ea478-a76e-4a96-b24b-9d2d99c8cbbd"
/>|<img width="736" height="339" alt="Screenshot 2026-07-21 at 11 02 20"
src="https://github.com/user-attachments/assets/bb154d29-bff4-4add-80d0-f92f2cd091e4"
/>|
## 📝 Checklist
- [x] CI successfully passed
- [x] I added new mocks and corresponding unit-tests if library API was
changed K
Kirill Zyusko committed
2bb2323ee170cb6478a3b6f560688eae478d2109
Parent: d29b28d
Committed by GitHub <noreply@github.com>
on 7/21/2026, 10:04:16 AM