Organism
Slides
Requires <UIProvider> — Getting Started →
Installation
Install just this component (copies the source into your project, no npm dependency)
npx orn-ui add slidesOr install the whole package and import it
pnpm add orn-ui
import { Slides } from 'orn-ui/slides';Usage
- when to use — Onboarding, a feature tour, a carousel. Anything that is one full panel at a time rather than a list.
- data / keyExtractor / renderItem — Generic over the item type, like a list: the slide content is yours to render.
- background — Per slide: one colour paints flat, several become a Gradient behind the content.
- autoPlay / interval — Advances on its own and pauses while a finger is dragging. showAutoPlayToggle is on by default because content that moves on its own needs a way to stop it (WCAG 2.2.2).
- indicators / indicatorPlacement — Dots or numbers, laid over the slide in white or outside it in theme colours.
- index / defaultIndex / onIndexChange — Controlled or uncontrolled, the same pair as the rest of the library.
Demo clip not recorded yet — see MEDIA.md
Variants
horizontal · gradient · dots · infinite + autoPlay
<View style={STAGE}>
<Slides
data={SLIDES}
keyExtractor={(item) => item.id}
background={(item) => item.gradient}
renderItem={(item) => <Panel slide={item} />}
loop
autoPlay
interval={2500}
/>
</View>numbered indicators · flat colors · finite · button inside
<View style={{ width: '100%', gap: 8 }}>
<View style={STAGE}>
<Slides
data={SLIDES}
keyExtractor={(item) => item.id}
background={(item, index) => FLAT[index]}
renderItem={(item) => <Panel slide={item} onPress={() => setTapped(item.title)} />}
indicators="numbers"
/>
</View>
<Body>{tapped ? `pressed: ${tapped}` : 'press the button inside a slide'}</Body>
</View>vertical orientation
<View style={STAGE}>
<Slides
data={SLIDES}
keyExtractor={(item) => item.id}
background={(item) => item.gradient}
renderItem={(item) => <Panel slide={item} />}
orientation="vertical"
/>
</View>Full demo source
const variants: VariantDef[] = [
{
label: 'horizontal · gradient · dots · infinite + autoPlay',
content: (
<View style={STAGE}>
<Slides
data={SLIDES}
keyExtractor={(item) => item.id}
background={(item) => item.gradient}
renderItem={(item) => <Panel slide={item} />}
loop
autoPlay
interval={2500}
/>
</View>
),
},
{
label: 'numbered indicators · flat colors · finite · button inside',
content: (
<View style={{ width: '100%', gap: 8 }}>
<View style={STAGE}>
<Slides
data={SLIDES}
keyExtractor={(item) => item.id}
background={(item, index) => FLAT[index]}
renderItem={(item) => <Panel slide={item} onPress={() => setTapped(item.title)} />}
indicators="numbers"
/>
</View>
<Body>{tapped ? `pressed: ${tapped}` : 'press the button inside a slide'}</Body>
</View>
),
},
{
label: 'vertical orientation',
content: (
<View style={STAGE}>
<Slides
data={SLIDES}
keyExtractor={(item) => item.id}
background={(item) => item.gradient}
renderItem={(item) => <Panel slide={item} />}
orientation="vertical"
/>
</View>
),
},
];Props
Also accepts testID, forwarded to the root node. It exists for end-to-end tests (Maestro drives the app by the accessibility tree) and has no effect on how the component looks or behaves.
| Name | Type | Default | Description |
|---|---|---|---|
data | T[] | — | — |
keyExtractor | (item: T, index: number) => string | — | — |
renderItem | (item: T, index: number) => ReactNode | — | Slide content: images, buttons, whatever. Drawn on top of `background`. |
background? | (item: T, index: number) => SlideBackground | — | Background per slide: `'#101014'` paints flat, `['#004cef', '#00cae1']` makes a gradient. |
gradientDirection? | 'vertical' | 'horizontal' | 'diagonal' | 'diagonal-reverse' | vertical | Direction of the gradient when `background` returns several colours. |
orientation? | 'vertical' | 'horizontal' | horizontal | — |
indicators? | 'dots' | 'numbers' | 'none' | dots | Circles, numbered circles, or none. |
indicatorPlacement? | 'overlay' | 'outside' | overlay | 'overlay' rests them on the slide, in white; 'outside' moves them out of the swipeable area, in theme colours. |
loop? | boolean | false | After the last one it goes back to the first (and the other way round). |
autoPlay? | boolean | false | Advances on its own. Pauses while a finger is dragging. |
interval? | number | 4000 | ms between `autoPlay` advances. |
showAutoPlayToggle? | boolean | true | Button to stop the automatic advance. Only appears with `autoPlay`, and defaults to `true` because content that moves on its own needs a way to pause it (WCAG 2.2.2). |
spacing? | number | 0 | Gap between slides, in px. At 0 they sit flush. |
index? | number | — | Controlled index. Without it, the component keeps its own starting from `defaultIndex`. |
defaultIndex? | number | 0 | — |
onIndexChange? | (index: number) => void | — | — |
height? | number | 240 | Height of the swipeable area. |
swipeEnabled? | boolean | true | — |
slideStyle? | StyleProp<ViewStyle> | — | Styles for the visible box of each slide — padding, alignment, radius. |
style? | StyleProp<ViewStyle> | — | — |