# Slides

> Organism — orn-ui

> ⚠️ Requires <UIProvider>: This component (like every orn-ui component) must render inside a <UIProvider> ancestor, or it throws at runtime. See https://orn-ui-docs.vercel.app/getting-started.md

> Runs on Expo SDK 54, 55, 56 and 57, and on bare React Native >=0.81 with react >=19.1. No native modules — works in Expo Go, no prebuild.

## Installation

Install just this component (copies the source into your project, no npm dependency)
```bash
npx orn-ui add slides
```

Or install the whole package and import it
```tsx
pnpm add orn-ui
import { Slides } from 'orn-ui/slides';
```

Depends on: core (theme + icons), transition, gradient

## Variants

### horizontal · gradient · dots · infinite + autoPlay

```tsx
<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

```tsx
<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

```tsx
<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

```tsx
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

| 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>` | — | — |
