Lynx UI logo
Lynx UI

<Scrollview>

A ScrollView component for ReactLynx. It provides scrolling primitives and bounce handling.
  • Lazy-loading optimized container powered by LazyComponent, designed to reduce first-screen rendering time

  • Built-in platform-consistent bounces behavior (iOS/Android alignment)

Info

You can check the source code to understand how it works, and you're welcome to submit MRs to enhance its capabilities.

Basic Usage
Under the `bounceableOptions`

Basic Usage

Use <ScrollView> to enable scrollable content.

ScrollViewProps

Properties

androidTouchSlop
Android
Typedefault | paging
Android touch recognition mode. When inside a component that supports 'paging' mode, 'paging' must be enabled.
bounceable
iOS
Android
Typeboolean
Enable bouncing effect
bounceableOptions
iOS
Android
Typeboolean | {alwaysBouncing?: boolean, debugLog?: boolean, enableBounceEventInFling?: boolean, enableBounces: boolean, endBounceTriggerDistance?: number, estimatedHeight?: number, estimatedWidth?: number, lowerBounceItem?: any, onScrollToBounces?: (e: {direction: upper | lower}) => void, singleSidedBounce?: upper | lower | both | iOSBounces | none, startBounceTriggerDistance?: number, upperBounceItem?: any, validAnimationVersion?: boolean}·Default{ enableBounces: true, singleSidedBounce: "iOSBounces" },
Props for bouncing effect
children
iOS
Android
TypeReactNode
Children in scroll-view.
className
iOS
Android
Harmony
Typestring
className
debugLog
iOS
Android
Harmony
Typeboolean·Defaultfalse
Display debug logs for bounce interactions.
enableRTL
iOS
Android
Harmony
Typeboolean·Defaultfalse
Whether horizontal bounce direction should be mirrored in RTL mode.
enableScroll
iOS
Android
Harmony
Typeboolean·Defaulttrue
Enable scroll interaction.
enableScrollMonitor
iOS
Android
Harmony
Typeboolean·Defaultfalse
Enable scroll monitor.
estimatedItemStyle
iOS
Android
TypeCSSProperties
Estimated height and width of the items need to be set.
exposureBottom
iOS
Android
Typestring·Default'10px'
exposure-screen-margin-bottom
exposureID
iOS
Android
Harmony
Typestring
exposure-id for global exposure
exposureLeft
iOS
Android
Typestring·Default'10px'
exposure-screen-margin-left
exposureRight
iOS
Android
Typestring·Default'10px'
exposure-screen-margin-right
exposureScene
iOS
Android
Harmony
Typestring
exposure-scene for global exposure
exposureTop
iOS
Android
Typestring·Default'10px'
exposure-screen-margin-top
firstScreenItemCount
iOS
Android
Typenumber·Default1
Estimated first screen item count for lazy rendering. Remaining children will complete rendering based on exposure. When this estimate is small, it may cause a blank screen phenomenon where some nodes exist on the first screen.
horizontal
iOS
Android
Typeboolean
Horizontal scroll.
iOSBounces
iOS
Android
Typeboolean·Defaulttrue
Open the bouncing effect on iOS. If you want to use it on Android, please refer to the bounceableOption. If the bounceableOption is set, the iOSBounces property will be invalid.
lazy
iOS
Android
Typeboolean·Defaulttrue
When enabled, only the items that are about to enter the viewport are rendered, reducing initial load time and memory usage; remaining items are rendered as they approach visibility during scroll.
lazyOptions
iOS
Android
TypeLazyOptions·Defaulttrue
When enabled, only the items that are about to enter the viewport are rendered, reducing initial load time and memory usage; remaining items are rendered as they approach visibility during scroll.
main-thread:gesture
iOS
Android
TypeBaseGesture
If you want to use gesture, pass it here.
onUIAppear
iOS
Android
Harmony
Type(e: CommonEvent) => void
Exposure event for UI
onUIDisappear
iOS
Android
Harmony
Type(e: CommonEvent) => void
Disappear event for UI
scene
iOS
Android
Typestring
Be used to mark the exposure timing of lazy loading. Please ensure that it is unique throughout the page.
scrollMonitorTag
iOS
Android
Harmony
Typestring·Defaultfalse
The tag for scroll monitor.
scrollOrientation
iOS
Android
Harmony
Typevertical | horizontal·Default'vertical'
Set to 'vertical' for vertical scrolling and set to 'horizontal' for horizontal scrolling.
scrollPropagationBehavior
iOS
Android
TypeScrollPropagationBehaviorOption·Default'native'
Controls whether scroll events propagate to parent containers. For now, 'preventPropagate' needs to be used together with temporaryBlockScrollClass and temporaryBlockScrollTag on iOS.
scrollviewId
iOS
Android
Typestring·Default"scrollview"
The id of the scrollview.
sticky
iOS
Android
TypeReactElement
Sticky item, designed for Tabs.
style
iOS
Android
Harmony
TypeCSSProperties
style
temporaryBlockScrollClass
iOS
Typestring·Default'BDXLynxViewPager'
The specific class name of the container that is blocked when 'scrollPropagationBehavior' is set to be 'preventPropagate', must be informed by the container provider. For now, 'preventPropagate' needs to be used together with temporaryBlockScrollClass and temporaryBlockScrollTag on iOS.
temporaryBlockScrollTag
iOS
Typenumber·Default0
Used to specify the native container tag that is blocked when 'scrollPropagationBehavior' is set to be 'preventPropagate', corresponding to the Tag attribute of UIView. Needs to be specified by the native container provider. For now, 'preventPropagate' needs to be used together with temporaryBlockScrollClass and temporaryBlockScrollTag on iOS.
temporaryNestedScroll
Android
Typeboolean
Android-only temporary flag to control nested scroll; maps to native 'enable-nested-scroll'. Android default value is true.
testing
iOS
Android
Typeboolean
Testing Mode.

Events

catchLongPress
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Same as onLongPress, but stops the event from propagating to parent elements.
catchTouchCancel
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Same as onTouchCancel, but stops the event from propagating to parent elements.
catchTouchEnd
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Same as onTouchEnd, but stops the event from propagating to parent elements.
catchTouchMove
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Same as onTouchMove, but stops the event from propagating to parent elements.
catchTouchStart
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Same as onTouchStart, but stops the event from propagating to parent elements.
onContentSizeChange
iOS
Android
Type(res: Record<string, unknown>) => void
Being triggered when scrolling content changes.
onLayoutChange
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Send when UI has changed viewport size.
onLongPress
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Send when a touch-point is held on the UI for a period of time.
onScroll
iOS
Android
Type(e: ScrollEvent) => void
Being triggered when scrolling occurs.
onScrollEnd
iOS
Android
Type(e: [object Object] | undefined) => void·Defaultundefined
Being triggered when scrolling stops.
onScrollToLower
iOS
Android
Type(e: [object Object] | undefined) => void·Defaultundefined
Being triggered when scrolling to lower.
onScrollToUpper
iOS
Android
Type(e: [object Object] | undefined) => void·Defaultundefined
Being triggered when scrolling to upper.
onTap
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Send when a touch-point is tapped on the UI.
onTouchCancel
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Send when a touch event is interrupted or cancelled before it is completed.
onTouchEnd
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Send when a touch-point is removed from the UI.
onTouchMove
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Send when a touch-point is moving on the UI.
onTouchStart
iOS
Android
Harmony
Type(e: EventHandler | undefined) => void
Send when a touch-point is placed on the UI.

BounceableBasicProps

alwaysBouncing
iOS
Android
Harmony
Typeboolean·Defaulttrue
Whether the scrollable container can bounce when the content area of the scrollable container is smaller than the viewport area.
debugLog
iOS
Android
Harmony
Typeboolean·Defaultfalse
Display debug logs. Open it when you find a bug.
enableBounceEventInFling
iOS
Android
Harmony
Typeboolean·Defaultfalse
Trigger bounces effect during fling
enableBounces
iOS
Android
Harmony
Typeboolean
Whether to enable bounce effect
endBounceTriggerDistance
iOS
Android
Harmony
Typenumber·Default0
The threshold distance of lower bounces, in pixels, when triggering the scrollToBounces event
estimatedHeight
iOS
Android
Harmony
Typenumber
Unit: px. Optional size hint for bounce effect. Recommended when used in List or <list/>.
estimatedWidth
iOS
Android
Harmony
Typenumber
Unit: px. Optional size hint for bounce effect. Recommended when used in List or <list/>.
lowerBounceItem
iOS
Android
Harmony
Typeany
Content of lower bounces view, which will be displayed during the lower bouncing effect.
singleSidedBounce
iOS
Android
Harmony
Typeupper | lower | both | iOSBounces | none·Default'both'
The direction of the bounce effect. 'both' for bouncing on both ends, 'none' to disable bounce, and 'upper'/'lower' for bouncing on either end
startBounceTriggerDistance
iOS
Android
Harmony
Typenumber·Default0
The threshold distance of upper bounces, in pixels, when triggering the scrollToBounces event
upperBounceItem
iOS
Android
Harmony
Typeany
Content of upper bounces view, which will be displayed during the upper bouncing effect.
validAnimationVersion
iOS
Android
Harmony
Typeboolean·Defaultfalse
requestAnimationFrame don't work under lynx version 2.15.2. This switch should be opened when the version is higher than 2.15.2.
onScrollToBounces
iOS
Android
Harmony
Type(e: {direction: upper | lower}) => void·Default0
When bounces effect is triggered and the bounce distance is larger than startBounceDistance or endBounceDistance on the upper or lower side, the scrollToBounces event will be triggered.

scrollToBouncesInfo

direction
Typeupper | lower

How to understand properties in useBounces

Let's see how useBounces is implemented. This hook can be attached to any scrollable container.

Inputs and Outputs

First, let's treat this hook as a black box that receives component settings and returns a series of methods to handle scroll container events:

  • Input: options

  • id: The scrollable container's id (required to avoid conflicts between identical containers on the same page).

  • scrollOrientation: Container scrolling direction (horizontal or vertical).

  • bounceableOptions: Additional hook configuration:

  • enableBounces: Whether to enable the bounce effect.

  • startBounceTriggerDistance/endBounceTriggerDistance: Thresholds for triggering onScrollToBounces (e.g., for "swipe-to-navigate" scenarios).

  • enableBounceEventInFling: Whether to trigger bounce effects during momentum scrolling.

  • upperBounceItem/lowerBounceItem: Content displayed in bounce areas.

  • alwaysBouncing: Enables bounce effects even when the container isn't scrollable.

  • singleSidedBounce: Restricts bounce effects to one side only.

  • onScrollToBounces: Triggered when bounce distance exceeds thresholds (filters minor bounces).

  • Output: Methods for binding to scroll containers:

  • main-thread:bindtouchstart/main-thread:bindtouchend/main-thread:bindtouchmove: Handles touch events.

  • main-thread:bindlayoutchange: Tracks container dimensions.

  • main-thread:bindscroll/main-thread:bindscrollend: Handles scroll events.

  • onUpperExposure/onUpperDisexposure/onLowerExposure/onLowerDisexposure: Manages container boundary states (bounce only occurs at edges).

Scroll Simulation

We use MTS and transform to simulate bounce effects:

  1. Locate nodes via lynx.querySelector:
lynx.querySelector(`#${containerID}`)
  1. Apply transform based on scroll curves from touch events:

useBounces divides scrolling into three phases:

  1. Rubber-band effect during touchmove

  2. Momentum scrolling

  3. Bounce-back effect

Using bounceableOptions

onScrollToBounces with distance thresholds

This event triggers only after completed bounces, requiring:

  1. The container must be in a bounce zone at touchEnd (not in neutral area).

  2. The bounce effect must fully complete (container returns to edge). The event fires only if the maximum bounce distance exceeds the threshold.

enableBounceEventInFling

When enabled (default), momentum scrolling can trigger bounces if the container reaches edges mid-fling. Disable this for bounce effects that require explicit touch gestures.

Where will upperBounceItem/lowerBounceItem show up?

These appear exclusively in bounce zones. When unset, the translated container reveals underlying content.

alwaysBouncing

Forces edge detection even when the container isn't scrollable, allowing bounce effects without actual scrolling.

Except as otherwise noted, this work is licensed under a Creative Commons Attribution 4.0 International License, and code samples are licensed under the Apache License 2.0.