Skip to content

fix: Invalid ScrollView position on input focus#431

Merged
MatiPl01 merged 2 commits intomainfrom
fix/invalid-scrollview-position-on-input-focus
Jul 26, 2025
Merged

fix: Invalid ScrollView position on input focus#431
MatiPl01 merged 2 commits intomainfrom
fix/invalid-scrollview-position-on-input-focus

Conversation

@MatiPl01
Copy link
Copy Markdown
Owner

@MatiPl01 MatiPl01 commented Jul 25, 2025

Description

Issue description

This PR fixes invalid ScrollView behavior when the TextInput component was focused. I noticed that this is caused by the fact that all items rendered within the sortable component use transforms for positioning (as transforms are said to be faster than top/left props).

Unfortunately, the position of the ScrollView is adjusted based on the render position of the TextInput component but in our case all items are rendered in the top left corner of the sortable component container and then transformed to their proper positions on the screen.

Solution

I decided to replace transforms with top and left layout props which seem to work fine.

Test example

Before After
Screen_recording_20250726_010612.mp4
Screen_recording_20250726_010142.mp4
Source code
import { useCallback } from 'react';
import { TextInput, View } from 'react-native';
import Animated, { useAnimatedRef } from 'react-native-reanimated';
import Sortable, { type SortableGridRenderItem } from 'react-native-sortables';

const testData = new Array(50).fill(0).map((_, i) => ({
  id: i,
  name: `Exercise ${i}`
}));

export default function PlaygroundExample() {
  const scrollableRef = useAnimatedRef<Animated.ScrollView>();

  const renderExerciseItem = useCallback<
    SortableGridRenderItem<(typeof testData)[0]>
  >(
    ({ item }) => (
      <View style={{ backgroundColor: '#ef4444', height: 160 }}>
        <TextInput
          keyboardType='numeric'
          placeholder={`TextInput#${item.id}`}
        />
      </View>
    ),
    []
  );

  return (
    <Animated.ScrollView
      contentContainerStyle={{ padding: 16, paddingBottom: 128, gap: 16 }}
      keyboardShouldPersistTaps='handled'
      ref={scrollableRef}>
      <Sortable.Grid
        activeItemScale={1.02}
        columnGap={40}
        columns={1}
        data={testData}
        enableActiveItemSnap={false}
        overDrag='vertical'
        renderItem={renderExerciseItem}
        rowGap={10}
        scrollableRef={scrollableRef}
      />
    </Animated.ScrollView>
  );
}

@MatiPl01 MatiPl01 self-assigned this Jul 25, 2025
@MatiPl01 MatiPl01 added enhancement New feature or request fix performance labels Jul 25, 2025
@vercel
Copy link
Copy Markdown

vercel Bot commented Jul 25, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
react-native-sortables-docs ⬜️ Ignored (Inspect) Visit Preview Jul 25, 2025 11:02pm

@MatiPl01
Copy link
Copy Markdown
Owner Author

Performance

Interestingly, the performance got even better on android. It seems that the application of transforms on android is slow and it is better to use theoretically slower layout props to position items, so this PR will also introduce better performance of items reordering.

Test example

The test example consists of 300 animated views which position is changed either via x and y translation or via the top/left layout position.

Fabric (New Arch)

Slightly faster with layout props

transform top/left
Screen_recording_20250726_004111.mp4
Screen_recording_20250726_004133.mp4

Paper (Old Arch)

Almost 2 times faster with layout props

transform top/left
Screen_recording_20250726_003919.mp4
Screen_recording_20250726_003851.mp4

@MatiPl01 MatiPl01 marked this pull request as ready for review July 25, 2025 23:08
@MatiPl01 MatiPl01 requested a review from Copilot July 25, 2025 23:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes an issue where ScrollView positioning was incorrect when TextInput components inside sortable items received focus. The problem occurred because sortable items used CSS transforms for positioning, which caused the ScrollView to calculate incorrect positions based on the original render location rather than the transformed position.

  • Replaced transform-based positioning with layout properties (top/left)
  • Removed architecture-specific positioning logic and the isPaper() utility function
  • Simplified the positioning system by using a single position reference instead of separate initial and current positions

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
useItemStyles.ts Core fix replacing transform positioning with layout props and simplifying position management
platform.ts Removed unused isPaper() function that was checking for Paper architecture
SortableGrid.tsx Changed flexBasis from undefined to 'auto' for better layout behavior

Comment thread packages/react-native-sortables/src/components/SortableGrid.tsx
@MatiPl01 MatiPl01 merged commit 2693234 into main Jul 26, 2025
7 checks passed
@MatiPl01 MatiPl01 deleted the fix/invalid-scrollview-position-on-input-focus branch July 26, 2025 07:08
@MatiPl01
Copy link
Copy Markdown
Owner Author

Well, performance is not improved then the onLayout callback is used. It gets even worse, so this PR doesn't really improve perf and makes it even worse. Unfortunately, there is no easy way to ensure that the input works properly so I will leave it with a worse perf for now and will have to reimagine the entire implementation in the future - likely in the sortables v2.

MatiPl01 added a commit that referenced this pull request Jul 27, 2025
## Description

Small improvement for perf issues after #431
MatiPl01 pushed a commit that referenced this pull request Jul 29, 2025
# [1.8.0](v1.7.1...v1.8.0) (2025-07-29)

### Bug Fixes

* Allow disabling default layer provider ([#424](#424)) ([ded5c92](ded5c92)), closes [#417](#417) [#36877](https://github.com/MatiPl01/react-native-sortables/issues/36877)
* Buggy grid swapping in some edge cases ([#414](#414)) ([3617f86](3617f86))
* DragProvider drag end index assignment ([#411](#411)) ([69ad8a6](69ad8a6))
* Hiding of the sortable item when teleported ([#436](#436)) ([4c3796f](4c3796f))
* Invalid flex container height on initial render and other small issues ([#437](#437)) ([48e905b](48e905b))
* Invalid ScrollView position on input focus ([#431](#431)) ([2693234](2693234)), closes [#ef4444](https://github.com/MatiPl01/react-native-sortables/issues/ef4444)
* Long drop duration reordering issues ([#406](#406)) ([ace7037](ace7037))
* Multiple minor improvements ([#439](#439)) ([f9d83e3](f9d83e3))
* Paper flickering and positioning issues ([#426](#426)) ([744e291](744e291))
* Teleported active item flickering ([#405](#405)) ([1413af2](1413af2))

### Features

* Base multi zone provider ([#409](#409)) ([56f0ef3](56f0ef3))
* Base zone with event callbacks ([#413](#413)) ([e51ca61](e51ca61))
* Fixed items support in sortable flex ([#416](#416)) ([1d23fcc](1d23fcc)), closes [#374](#374)
* Max overscroll settings ([#423](#423)) ([167dc4e](167dc4e)), closes [#419](#419)
* Separate controlled item dimensions from measured dimensions ([#433](#433)) ([cad95e5](cad95e5))

### Performance Improvements

* Merge item decoration styles with position styles ([#407](#407)) ([5066edd](5066edd))
* More performant items reordering ([#435](#435)) ([be78141](be78141))
* Reduce the number of unnecessary onLayout calls ([#434](#434)) ([ce56159](ce56159)), closes [#431](#431)
* Replace useSharedValue with useMutableValue ([#408](#408)) ([6994c7a](6994c7a))
@MatiPl01
Copy link
Copy Markdown
Owner Author

🎉 This issue has been resolved in version 1.8.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request fix released

Projects

None yet

2 participants