Skip to content
Back to skills

Lynx Ui Scroll Coordinator

ASecurity

Coordinate a collapsible header and persistent toolbar with nested lists, vertical scroll views, or paged content, including whole-page and per-page pull-to-refresh.

  • 119 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added October 1, 2026
design

Security analysis

A100/100

Pro scans all 18 files and shows the line behind each finding

Scanned October 1, 2026

npx -y skills add lynx-family/lynx-ui --skill lynx-ui-scroll-coordinator --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Lynx Ui Scroll Coordinator?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Lynx Ui Scroll Coordinator
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/lynx-family-lynx-ui-scroll-coordinator/badge)](https://www.skillsdirectory.com/skills/lynx-family-lynx-ui-scroll-coordinator)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: scroll-coordinator
description: Coordinate a collapsible header and persistent toolbar with nested lists, vertical scroll views, or paged content, including whole-page and per-page pull-to-refresh.
---

# lynx-ui-scroll-coordinator

Import `ScrollCoordinator` and `ScrollCoordinatorRef` from `@lynx-js/lynx-ui`. Give the component a bounded height and put a vertical `List`, `ScrollView`, or `ViewPager` of lists in `slot`. The component generates `scroll-coordinator`, `scroll-coordinator-header`, `scroll-coordinator-toolbar`, and `scroll-coordinator-slot` native elements.

## Composition

`headers` contains the collapsible content. `toolbar` stays visible; the collapse distance is header height minus toolbar height. A toolbar can overlay the header, so reserve room for it in your header layout. Use a `scroll-coordinator-slot-drag` with `enable-drag={false}` around tabs when vertical drags on the tabs should not collapse the header.

`className` and `style` size and style the outermost element. With a `refreshOptions` object, this is the `refresh` wrapper. Otherwise it is the native coordinator. All structural styles are minimal; style supplied content with your own design system. `.ui-sticky` is applied to the coordinator and its optional outer refresh wrapper at the sticky threshold.

## Refresh

For whole-page refresh, provide `refreshOptions={{ enableRefresh: true, headerContent, onStartRefresh }}`. Its callback names and payloads match FeedList, with an independent native implementation and no `mode` option. Use `startRefresh()` to trigger a refresh and always call `finishRefresh()` after the operation settles, including failures. Returning a promise does not finish the animation automatically.

Disable `bounces` on Lists inside a whole-page refresh coordinator so the outer refresh owns the pull gesture and rebound.

Give `headerContent` a nonzero height and keep its dimensions stable while refreshing to avoid resetting the native header position. `onRefreshOffsetChange` receives `{ offset, headerSize, isDragging }` in px, and `onHeaderReleased` receives the last offset and current header size. `onStartRefresh` reports `triggeredBy: 'drag' | 'startRefresh'`. `onRefreshStateChange` forwards the native numeric state; use `isDragging` to track pulling because native refresh does not synthesize the hook implementation's dragging state.

Set `enableRefresh: false` to disable new refreshes without remounting nested content. An active operation can still call `finishRefresh()`. Passing `refreshOptions={false}` or omitting it removes the wrapper.

For independent page refresh, set `refreshInSlot` and put a FeedList with `refreshOptions={{ ...options, mode: 'native' }}` inside each page. Finish each page's refresh through its own FeedList ref. Enabled outer refresh takes precedence when both are requested.

## Navigation and events

Use `scrollTo(offset, animated)`, `scrollToTop(animated)`, `scrollToSticky(animated)`, and `scrollIntoView(headerChildId, animated)`. These control the header only; nested lists retain their own offsets. `scrollIntoView` targets an ID inside `headers`; IDs must be unique on the page. Commands use instance-local refs so multiple coordinators do not share a refresh or scroll target.

`onOffsetChange` receives `{ offset, height }` in px. `main-thread:onOffsetChange` receives the same payload and requires a `'main thread'` callback. Sticky transitions use `granularity` as their tolerance and fire once per transition. Zero-height headers do not enter the sticky state.

Pass raw native properties explicitly through `coordinatorProps`. Component-managed properties take precedence. `popupOptions` applies only to native hosts supporting popup expansion; normal pages do not need it.

The native host must register the public `scroll-coordinator*` and `refresh*` elements. Hosts using legacy registrations can enable the Lynx 4.0+ `syncXElementRegistry` page configuration. Renaming JSX tags alone cannot add missing native implementations.

## Prompt formula

“Build a bounded ScrollCoordinator with [header], [persistent toolbar], and [vertical list or paged content]. Use [outer refresh or per-page refresh], finish every refresh, preserve nested scroll positions, and use LUNA styles with enough safe-area padding.”

Files in this skill

  • CHANGELOG.md663 B
  • LICENSE11.1 KB
  • README.md810 B
  • README_zh.md733 B
  • SKILL.md4.2 KB
  • __tests__/ScrollCoordinator.test.tsx13.4 KB
  • docs/APIReference.mdx15.3 KB
  • docs/README.mdx517 B
  • docs/README.zh.mdx499 B
  • package.json1.2 KB
  • rslib.config.ts338 B
  • src/index.tsx7.1 KB
  • src/styles.css709 B
  • src/types/index.docs.ts7.4 KB
  • src/types/index.ts225 B
  • tsconfig.docs.json122 B
  • tsconfig.json225 B
  • vitest.config.ts528 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.