ScrollViewReader

The ScrollViewReader component equivalent to SwiftUI’s ScrollViewReader, allowing scripts to programmatically control scrolling position within scrollable content such as List or ScrollView.


ScrollViewProxy

ScrollViewProxy represents the programmatic interface for controlling scrolling. It is provided by ScrollViewReader during rendering.

1interface ScrollViewProxy {
2    scrollTo: (id: string | number, anchor?: KeywordPoint | Point) => void
3}

Methods

scrollTo(id, anchor?)

Scrolls the closest scrollable container until the element with the specified key becomes visible.

Parameters

Parameter Type Required Description
id string number Yes
anchor KeywordPoint Point No

KeywordPoint

Predefined scroll alignment keywords:

  • 'top'
  • 'center'
  • 'bottom'

Point

Precise alignment coordinates:

1type Point = {
2  x: number
3  y: number
4}

ScrollViewReader Component

1type ScrollViewReaderProps = {
2    children: (scrollViewProxy: ScrollViewProxy) => VirtualNode;
3};
4declare const ScrollViewReader: FunctionComponent<ScrollViewReaderProps>;

Props

Name Type Required Description
children (proxy: ScrollViewProxy) => VirtualNode Yes A function that receives a ScrollViewProxy and returns scrollable content.

Behavior and Usage Notes

  1. ScrollViewReader must wrap a List, ScrollView, or another scrollable container.
  2. The proxy is created once during rendering. Use useRef if you need to store it.
  3. scrollTo works only with elements that have a unique key.
  4. Using withAnimation enables smooth scrolling.
  5. The API follows React’s identity model, but scroll behavior matches SwiftUI.

Example Usage

1import {
2  Button,
3  Navigation,
4  NavigationStack,
5  Script,
6  Text,
7  List,
8  ScrollViewReader,
9  ScrollView,
10  VStack,
11  useRef,
12  ScrollViewProxy,
13  withAnimation
14} from "scripting"
15
16
17function Item({ index }: { index: number }) {
18  return <Text>
19    Item - {index}
20  </Text>
21}
22
23function View() {
24  const dismiss = Navigation.useDismiss()
25  const proxyRef = useRef<ScrollViewProxy>()
26
27  return <NavigationStack>
28    <VStack navigationTitle="ScrollViewReader">
29
30      <ScrollViewReader>
31        {(proxy) => {
32          // Store the proxy instance
33          proxyRef.current = proxy
34
35          return <List>
36            {new Array(100).fill(0).map((_, index) =>
37              <Item
38                key={index}
39                index={index}
40              />
41            )}
42            <Text key="bottom">
43              Bottom
44            </Text>
45          </List>
46        }}
47      </ScrollViewReader>
48
49      <Button
50        title="Jump"
51        action={() => {
52          if (proxyRef.current == null) {
53            console.log("no proxy found")
54            return
55          }
56
57          const index = Math.random() * 100 | 0
58
59          withAnimation(() => {
60            proxyRef.current?.scrollTo(index)
61
62            // Scroll to the element identified by key="bottom"
63            // proxyRef.current?.scrollTo("bottom", "bottom")
64          })
65        }}
66      />
67
68    </VStack>
69  </NavigationStack>
70}
71
72async function run() {
73  await Navigation.present({
74    element: <View />
75  })
76  Script.exit()
77}
78
79run()

How key Works in Scripting

Scripting does not support .id() as in SwiftUI. Instead:

1<Text key="bottom">Bottom</Text>
  • key identifies the element within the virtual node tree
  • scrollTo("bottom") will scroll to this element
  • key must be stable and unique, similar to React and SwiftUI’s .id()

Animation Support

Scroll operations can be wrapped in withAnimation to enable smooth transitions:

1withAnimation(() => {
2  proxy.scrollTo("targetKey", "center")
3})

The animation behavior follows SwiftUI’s animation engine.


Important Notes

  1. Every scroll target must have a unique key.
  2. scrollTo will not work without a matching key.
  3. The scrollable content must be inside the same ScrollViewReader.
  4. The alignment anchor is optional but useful for precise positioning.
  5. The API mirrors SwiftUI’s ScrollViewReader logic but adopts React-style identity handling.