Lynx

<scroll-coordinator> XElement

<scroll-coordinator> is a nested scroll coordination component for implementing coordinated scrolling between multiple scrollable containers. It is commonly used in sticky-header page layouts found in mainstream apps, and is typically combined with <viewpager> and <list> to build composite scenarios involving nested scrolling and tabbed paging.

Info

<scroll-coordinator> coordinates nested structures through <scroll-coordinator-header> and <scroll-coordinator-slot>, achieving the following behavior:

  • When the outer layer scrolls to the bottom, scroll control is automatically handed over to the inner layer
  • When the inner layer scrolls to the top, scroll control is automatically returned to the outer layer
  • The handover of scroll control is smooth and seamless
// ❌ Not supported: directly nesting scrollable containers
<scroll-view id="outer">
  <list id="inner" />
</scroll-view>

// ✅ Supported: using scroll-coordinator for coordinated nested scrolling
<scroll-coordinator>
  <scroll-coordinator-header id="outer" />
  <scroll-coordinator-slot>
    <list id="inner" />
  </scroll-coordinator-slot>
</scroll-coordinator>

Usage

The core layout requirement of <scroll-coordinator> is to control via CSS: scroll-coordinator height == scroll-coordinator-slot height + toolbar height.

Layout Guidelines

  • <scroll-coordinator>: vertical flex layout, display: flex; flex-direction: column;
  • <scroll-coordinator-header>: out of normal flow, position: absolute;
  • <scroll-coordinator-toolbar>: participates in layout, display: flex;
  • <scroll-coordinator-slot>: fills remaining space, flex: 1;
.coordinator {
  width: 100%;
  height: 100%
  display: flex;
  flex-direction: column;
}

.coordinator-toolbar {
  display: flex;
  width: 100%;
}

.coordinator-header {
  position: absolute;
  width: 100%;
}

.coordinator-slot {
  width: 100%;
  flex-direction: column;
  flex: 1;
}

Vertical Coordinated Scrolling

A <list> must be placed inside <scroll-coordinator-slot> to enable vertical coordinated scrolling

<scroll-coordinator class="coordinator">
  <scroll-coordinator-header class="coordinator-header">
    <Header />
  </scroll-coordinator-header>
  <scroll-coordinator-slot class="coordinator-slot">
    <list />
  </scroll-coordinator-slot>
</scroll-coordinator>

Horizontal Paged Scrolling

<scroll-coordinator-slot> can detect <viewpager> page switch events and re-bind the nested scroll relationship with the <list> inside.

<scroll-coordinator class="coordinator">
  <scroll-coordinator-header class="coordinator-header">
    <Header />
  </scroll-coordinator-header>
  <scroll-coordinator-slot class="coordinator-slot">
    <Tabs />
    <viewpager>
      <viewpager-item>
        <list />
      </viewpager-item>
    </viewpager>
  </scroll-coordinator-slot>
</scroll-coordinator>

Full-Page Pull-to-Refresh

Wrap <scroll-coordinator> with <refresh> and set refresh-mode="fold" bounces={true} to enable full-page pull-to-refresh

<refresh>
  <refresh-header>
    <Loading />
  </refresh-header>
  <scroll-coordinator class="coordinator" bounces={true} refresh-mode="fold">
    <scroll-coordinator-header class="coordinator-header">
      <Header />
    </scroll-coordinator-header>
    <scroll-coordinator-slot class="coordinator-slot">
      <viewpager>
        <viewpager-item>
          <list />
        </viewpager-item>
      </viewpager>
    </scroll-coordinator-slot>
  </scroll-coordinator>
</refresh>

Per-Tab Pull-to-Refresh

Wrap the <list> inside <scroll-coordinator-slot> with <refresh> and set refresh-mode="page" bounces={false} to enable per-tab pull-to-refresh

<scroll-coordinator class="coordinator" bounces={false} refresh-mode="page">
  <scroll-coordinator-header class="coordinator-header">
    <Header />
  </scroll-coordinator-header>
  <scroll-coordinator-slot class="coordinator-slot">
    <viewpager>
      <viewpager-item>
        <refresh>
          <refresh-header />
          <list />
        </refresh>
      </viewpager-item>
    </viewpager>
  </scroll-coordinator-slot>
</scroll-coordinator>

Attributes

android-nested-scroll-as-child

Android
// @defaultValue: false
'android-nested-scroll-as-child'?: boolean;

Android foldview is based on CoordinateLayout, but it only implements NestedScrollingParent, so it not support to nested scroll as child in other scrolling widget, set this property true to make it work.

bounces

iOS
Harmony
// @defaultValue: true
bounces?: boolean;

Enable the bounce effect when the coordinator scrolls past its boundary.

enable-scroll

Android
iOS
Clay
Harmony
// @defaultValue: true
'enable-scroll'?: boolean;

Set whether the coordinator can scroll vertically.

enable-scroll-bar

iOS
Harmony
// @defaultValue: false
'enable-scroll-bar'?: boolean;

Set whether the scrollbar is visible during coordinator scrolling.

granularity

Android
iOS
Clay
Harmony
// @defaultValue: 0.01
granularity?: number;

The event response granularity of bindoffset, once the scroll distance exceeds the scrollable distance of granularity, it may trigger. It defaults to 0.01, but it doesn't necessarily trigger every 0.01.

header-over-slot

Android
iOS
Clay
Harmony
// @defaultValue: false
'header-over-slot'?: boolean;

This property controls whether the header hierarchy higher than the slot, when header is overflow, it will be displayed on top of the slot. Otherwise, it will be displayed below the slot. It is better to set this property explicitly, rather than use the default value.

ios-force-scroll-detach

iOS
// @defaultValue: false
'ios-force-scroll-detach'?: boolean;

Whether to force the nested-vertical-scroll-behavior invalid of foldview on iOS, the setting is ineffective for other platforms

ios-scrolls-to-top

iOS
// @defaultValue: false
'ios-scrolls-to-top'?: boolean;

When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top. iOS feature only.

refresh-mode

iOS
// @defaultValue: 'none'
'refresh-mode'?: 'page' | 'none' | 'fold';

The pull-to-refresh mode of foldview, none (none, default value), page (category pull-to-refresh), fold (overall pull-to-refresh)

Events

Frontend can bind corresponding event callbacks to listen for runtime behaviors of the element, as shown below.

bindoffset

Android
iOS
Clay
Harmony
bindoffset = (e: ScrollCoordinatorOffsetEvent) => {};
FieldTypeOptionalDefaultPlatformsSinceDescription
heightnumberNo
Android
iOS
Clay
Harmony
The absolute value of the scrollable distance (header height - toolbar height), in px
offsetnumberNo
Android
iOS
Clay
Harmony
The absolute value of the header scroll offset, in px

Callback for folding progress

Methods

Frontend can invoke component methods via the SelectorQuery API.

setFoldExpanded


lynx.createSelectorQuery()
     .select('#id')
     .invoke({
      method: 'setFoldExpanded',
      params: {
        /**
         * Offset, supports px and rpx
         * @Android
         * @iOS
         * @Harmony
         * @Web
         * @PC
         */
        offset: string;
        /**
         * Whether folding requires animation
         * @Android
         * @iOS
         * @Harmony
         * @Web
         * @PC
         */
        smooth: boolean;
      };
      success: function (res) {},
      fail: function (res) {},
    })
    .exec();

Compatibility

LCD tables only load in the browser

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.