lynx-ui-swiper SKILL
Swiper is a high-performance, fully customizable carousel. It supports horizontal swiping, looping, auto-play, RTL, edge bounces, and both built-in and custom layouts/animations. This guide is written for AI code agents to generate correct, production-ready code with minimal back-and-forth.
1. Core Capabilities
- Horizontal swipe with inertial paging and configurable
durationand easing - Looping with
loopandloopDuplicateCount - Auto Play with
autoPlayandautoPlayInterval - Two layout modes:
mode='normal'andmode='custom' - Custom per-item animation via
main-thread:customAnimation(+customAnimationFirstScreenfor first screen rendering) - Edge bounce views with
bounceConfigand release callbacks - RTL support via
RTL(trueor'lynx-rtl') - Fine-grained touch-angle control via
consumeSlideEvent, and event coordination viablockNativeEvent - Imperative control with
SwiperRef(swipeNext,swipePrev,swipeTo,cancelAnimation)
2. AI Coding Guide
Minimal Usable Example
Each <Swiper> must provide data, itemWidth, and render children via a function that returns a <SwiperItem>.
import { Swiper, SwiperItem } from '@lynx-js/lynx-ui'
const data = ['red', 'green', 'blue']
function Example() {
return (
<Swiper data={data} itemWidth={300}>
{({ item, index }) => (
<SwiperItem>
<view
style={{ width: '100%', height: '200px', backgroundColor: item }}
>
<text>Item {index}</text>
</view>
</SwiperItem>
)}
</Swiper>
)
}
Render Props Mechanics
<Swiper>calls your children function once per item with{ item, index }.- You must return a single
<SwiperItem>as the root of that function; place your content inside it. - Use
indexfor app content such as labels, item lookup, and indicators.
Recommended Prompt Formula
Scenario + Layout Mode/Align + Sizes (
itemWidth,containerWidth) + Data + Interaction (loop, auto-play, bounces, RTL) + Callbacks + Optional custom animation
Examples:
- “Create a centered carousel with
spaceBetween=16, 5 items,itemWidth=350, an indicator, and Prev/Next buttons.” - “Implement looped auto-play Swiper (
autoPlayInterval=2500), alignstart, and an end bounce for ‘Show More’.” - “Build a
mode='custom'Swiper with scale and translateX animation usingmain-thread:customAnimation.”
3. Use Cases & Best Practices
- Basic Horizontal:
mode='normal'withmodeConfig.align(start/center/end) and optionalspaceBetween. - Loop & Auto Play: set
loop={true}andautoPlay={true}withautoPlayInterval. - Bounces: configure
bounceConfigwithstartBounceItem/endBounceItemand widths; release callbacks fire with{ type, offset }. Bounces are ignored whenloop=true. - Custom Animation: switch to
mode='custom'and providemain-thread:customAnimation(value, index) => style. Duplicate this logic incustomAnimationFirstScreenfor first-screen rendering. - RTL: set
RTL={true}orRTL={'lynx-rtl'}. The latter applies Lynx’sdirection: lynx-rtlexplicitly. - In Scroll Containers: when inside
scroll-viewor other vertical scrollers, setexperimentalHorizontalSwipeOnly={true}and, if native events are being swallowed, setblockNativeEvent={true}; tuneconsumeSlideEventif needed. - Indicators & Controls: derive
currentfromonChange, render an external indicator, and useSwiperRefto control navigation. - Container Sizing: set
containerWidthexplicitly (screen width minus paddings) to avoid mis-measure; usestyle={{ overflow: 'visible' }}if centered items need to bleed.
Loop + Auto Play Example
<Swiper
data={['red', 'green', 'yellow', 'purple']}
itemWidth={315}
itemHeight={220}
containerWidth={(lynx.__globalProps.screenWidth || 375) - 16}
loop
autoPlay
autoPlayInterval={2000}
mode='normal'
modeConfig={{ align: 'start', spaceBetween: 8 }}
experimentalHorizontalSwipeOnly
>
{({ item, index }) => (
<SwiperItem>
<view style={{ width: '100%', height: '100%', backgroundColor: item }} />
<text>Number.{index}</text>
</SwiperItem>
)}
</Swiper>
Bounces Example
Note: startBounceItemWidth / endBounceItemWidth default to 50. This example sets endBounceItemWidth to 100 to demonstrate a larger overscroll resistance range.
<Swiper
data={colors}
itemWidth={250}
itemHeight={200}
mode='normal'
bounceConfig={{
enable: true,
endBounceItemWidth: 100,
endBounceItem: (
<view style='display: linear; linear-orientation: vertical; height: 100%; width: 30px;'>
<text>Show More</text>
</view>
),
onEndBounceItemBounce: ({ type, offset }) => {
console.log('bounce', type, offset)
},
}}
>
{({ index }) => (
<SwiperItem>
{/* content */}
</SwiperItem>
)}
</Swiper>
Custom Animation Example (mode='custom')
import { interpolate, interpolateJS } from '@lynx-js/lynx-ui'
const ITEM_WIDTH = 250
function customAnimation(value: number) {
'main thread'
const scale = interpolate(value, [-1, 0, 1], [0.8, 1, 0.8])
const centerOffset = (lynx.__globalProps.screenWidth - ITEM_WIDTH) / 2
const translateX = interpolate(value, [-1, 0, 1], [
-ITEM_WIDTH + centerOffset,
centerOffset,
ITEM_WIDTH + centerOffset,
], 'extend')
return {
transform: `translateX(${translateX}px) scale(${scale})`,
'transform-origin': 'center',
}
}
function customAnimationFirstScreen(value: number) {
const scale = interpolateJS(value, [-1, 0, 1], [0.8, 1, 0.8])
const centerOffset = (lynx.__globalProps.screenWidth - ITEM_WIDTH) / 2
const translateX = interpolateJS(value, [-1, 0, 1], [
-ITEM_WIDTH + centerOffset,
centerOffset,
ITEM_WIDTH + centerOffset,
], 'extend')
return {
transform: `translateX(${translateX}px) scale(${scale})`,
'transform-origin': 'center',
}
}
<Swiper
data={colors}
itemWidth={ITEM_WIDTH}
itemHeight={200}
mode='custom'
main-thread:customAnimation={customAnimation}
customAnimationFirstScreen={customAnimationFirstScreen}
>
{({ index }) => (
<SwiperItem>
{/* content */}
</SwiperItem>
)}
</Swiper>
RTL Example
<Swiper
data={items}
itemWidth={350}
itemHeight={200}
mode='normal'
modeConfig={{ align: 'start', spaceBetween: 8 }}
RTL={true}
>
{({ index }) => (
<SwiperItem>
{/* content */}
</SwiperItem>
)}
</Swiper>
4. Props Highlights
data: array of items to render; consumed by children render functionitemWidth: per-item width in px; requireditemHeight: optional per-item height; omit for natural/content-driven heightcontainerWidth: Swiper container width; default tolynx.__globalProps.screenWidthmode:'normal' | 'custom'; affects item placementmodeConfig:{ align?: 'start' | 'center' | 'end'; spaceBetween?: number }for normal modeloop/loopDuplicateCount: enable loop and control cloned head/tail countautoPlay/autoPlayInterval: enable and tune auto pagingbounceConfig: edge views and behavior; ignored whenloop=trueoffsetLimit: limit offset to avoid blank edges, e.g.[0, containerWidth - itemWidth]consumeSlideEvent: angle windows for handling touches; default covers horizontalblockNativeEvent: when Swiper is inside other scroll containersRTL:trueor'lynx-rtl'onChange,onSwipeStart,onSwipeStop,main-thread:onOffsetChangemain-thread:easing,main-thread:customAnimation,customAnimationFirstScreen
5. Ref API
interface SwiperRef {
swipeNext(): void
swipePrev(): void
swipeTo(
index: number,
options?: { animate?: boolean, onFinished?: () => void },
): void
cancelAnimation(): void // use with caution
}
6. FAQ
- Do children have to be a function? Yes. It receives
{ item, index }and must return<SwiperItem>. - Why doesn’t
initialIndexupdate after mount? It is only applied at first screen; later updates are ignored. UseswiperKeyorresetOnReuseto reset. - My last item leaves a blank area when
align='start'. ProvideoffsetLimit={[0, containerWidth - itemWidth]}to clamp the range. - Bounces don’t trigger when
loop=true. Correct—bounce is ignored in looping. - I’m in a vertical
scroll-view, swipes feel conflicted. SetexperimentalHorizontalSwipeOnly={true}and considerblockNativeEvent={true}; adjustconsumeSlideEventif needed. - Why duplicate
customAnimationFirstScreen? It mirrorsmain-thread:customAnimationfor first-screen rendering until main-thread first-screen support arrives. - Opacity rendering glitches? Set
overlapon<SwiperItem>’s direct child as needed.