Core Concepts
Two contexts
Everything in @react-slides/core revolves around two nested React contexts.
PresentationContext — global, provided by <Presentation>:
slideIndex,totalSlides,modenext(),prev(),goTo(slide, step?),setMode(mode)
SlideContext — per-slide, provided by each <Slide>:
slideId,slideIndex,stepIndex,totalSteps,isActivenotes,meta
import { usePresentation, useSlide, usePresentationSlide } from '@react-slides/core'
const { slideIndex, next } = usePresentation()const { stepIndex, totalSteps } = useSlide()const both = usePresentationSlide() // mergedBuild 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 slidesPlugins
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'