Skip to content

Core Concepts

Two contexts

Everything in @react-slides/core revolves around two nested React contexts.

PresentationContext — global, provided by <Presentation>:

  • slideIndex, totalSlides, mode
  • next(), prev(), goTo(slide, step?), setMode(mode)

SlideContext — per-slide, provided by each <Slide>:

  • slideId, slideIndex, stepIndex, totalSteps, isActive
  • notes, meta
import { usePresentation, useSlide, usePresentationSlide } from '@react-slides/core'
const { slideIndex, next } = usePresentation()
const { stepIndex, totalSteps } = useSlide()
const both = usePresentationSlide() // merged

Build any custom UI from these — progress bars, navigators, overlays — without coupling to the rest of the framework.

Fragments

Fragments are step-gated children. They register with SlideContext in render order and receive sequential step numbers (1, 2, 3, …) automatically. Pass step to override.

exit makes a fragment disappear at a later step — useful for replace-in-place reveals.

import { Slide, Fragment } from '@react-slides/core'
const slides = () => {
return (
<>
<Slide>
<Fragment step={1} exit={3}>Visible on 1–2, gone on 3</Fragment>
<Fragment step={3}>Replaces the line above</Fragment>
</Slide>
</>
)
}
export default slides

Plugins

A plugin runs once when a <Presentation> mounts. It receives PluginContext — listen to events, register controls, query state.

interface Plugin {
name: string
setup(ctx: PluginContext): void | (() => void)
}
interface PluginContext {
getState(): PresentationState
on(event: 'slideChange' | 'stepChange' | 'modeChange', handler): void
registerControl(adapter: ControlAdapter): void
registerRenderer(name: string, renderer: ComponentType): void
}

Built-in plugins live in @react-slides/viewer: presenterMode(), autoplay(intervalMs).

Controls

Controls translate user input into navigation actions.

interface ControlAdapter {
name: string
setup(actions: NavigationActions): void | (() => void)
}
interface NavigationActions {
next(): void
prev(): void
goTo(slide: number, step?: number): void
setMode(mode: PresentationMode): void
}

Built-in controls in @react-slides/viewer: keyboard(), touch(), hashRouter(), remoteControl(url).

When using the CLI, controls and plugins come from react-slides.config.ts (scaffolded by react-slides init with keyboard() and touch()). The CLI wraps your slide entry in <PresentationViewer> and passes controls and plugins from that file. If no config exists, it warns and falls back to the same defaults. Use <Presentation> / <PresentationViewer> directly only when embedding react-slides without the CLI.

Modes

PresentationMode is 'present' | 'overview' | 'speaker'. The keyboard() control maps Escape to overview by default. Render different chrome based on mode using usePresentation().

State machine

Navigation is a pure reducer (presentationReducer) over PresentationState. Exposed for advanced cases — most users never touch it.

import { presentationReducer, createInitialState } from '@react-slides/core'