# Reelkit > Headless, virtualized, TikTok-style vertical slider component library for React, Vue, and Angular. Zero dependencies in core; renders only 3 slides to the DOM at any time via virtualization. This file indexes the Reelkit documentation so LLM agents can consume it without scraping the React-rendered site. Each link points at the public docs URL; fetch `llms-full.txt` for the same index with embedded per-page summaries. Each section below embeds the full hand-authored summary for every page — fetch this file instead of `llms.txt` when you want content inline. ## Getting started ### Getting Started URL: https://reelkit.dev/docs/getting-started # Getting Started reelkit = **single-item slider**. One item visible at time. Like TikTok, Instagram Reels, Stories. Good for vertical video feeds, fullscreen galleries, swipeable content. > [!WARNING] > ReelKit under active dev. While 0.x.x, APIs may change between minor versions, no deprecation period. Pin version to avoid breakage. ## Try It Online Try in browser, no install: - React Demo: https://react-demo.reelkit.dev/?utm_source=docs - React Starter (StackBlitz): https://stackblitz.com/github/KonstantinKai/reelkit-react-starter - Angular Demo: https://angular-demo.reelkit.dev/?utm_source=docs - Angular Starter (StackBlitz): https://stackblitz.com/github/KonstantinKai/reelkit-angular-starter - Vue Demo: https://vue-demo.reelkit.dev/?utm_source=docs - Vue Starter (StackBlitz): https://stackblitz.com/github/KonstantinKai/reelkit-vue-starter ## Quick Start Minimal vertical slider. ### React ```tsx import { Reel, ReelIndicator } from '@reelkit/react'; const items = [ { id: 1, title: 'Slide 1', color: '#6366f1' }, { id: 2, title: 'Slide 2', color: '#8b5cf6' }, { id: 3, title: 'Slide 3', color: '#ec4899' }, ]; function App() { return ( (
{items[index].title}
)} >
); } ``` ### Angular ```typescript import { Component } from '@angular/core'; import { ReelComponent, ReelIndicatorComponent, RkReelItemDirective, } from '@reelkit/angular'; const items = [ { id: 1, title: 'Slide 1', color: '#6366f1' }, { id: 2, title: 'Slide 2', color: '#8b5cf6' }, { id: 3, title: 'Slide 3', color: '#ec4899' }, ]; @Component({ standalone: true, imports: [ReelComponent, ReelIndicatorComponent, RkReelItemDirective], template: `
{{ items[i].title }}
`, }) export class AppComponent { readonly items = items; } ``` ### Vue ```vue ``` ## Key Concepts ### Reel `Reel` = main container. Manages slider state, handles touch gestures, keyboard nav, animations. Render prop pattern via `itemBuilder` for slides. ### itemBuilder `itemBuilder` prop = function. Gets index, returns slide content. Enables virtualization — only visible items render. ### ReelIndicator Optional. Instagram-style progress indicators. Shows current position. ### React example ```tsx import { Reel, ReelIndicator } from '@reelkit/react'; function App() { return ( } > ); } ``` ### Angular example ```html ``` ### Vue example ```vue-html ``` ## Navigation Built-in nav methods: - **Touch/Swipe:** Drag to navigate. Momentum + snap. - **Keyboard:** Arrow keys. Overlay components also handle Escape to close. - **Mouse Wheel:** Enable with `enableWheel` prop. - **Programmatic:** Use `apiRef` for `next()`, `prev()`, `goTo()`. ### React ```tsx import { useRef } from 'react'; import { Reel, type ReelApi } from '@reelkit/react'; function App() { const apiRef = useRef(null); return ( <> } /> ); } ``` ### Angular ```html ``` ### Vue ```vue ``` ## Next Steps - [Installation](/docs/installation) — all packages + setup options - [Core Guide](/docs/core/guide) — framework-agnostic engine - Framework Guide — React: [/docs/react/guide](/docs/react/guide), Angular: [/docs/angular/guide](/docs/angular/guide), Vue: [/docs/vue/guide](/docs/vue/guide) - Reel Player — React: [/docs/reel-player](/docs/reel-player), Angular: [/docs/angular-reel-player](/docs/angular-reel-player), Vue: [/docs/vue-reel-player](/docs/vue-reel-player) - Lightbox — React: [/docs/lightbox](/docs/lightbox), Angular: [/docs/angular-lightbox](/docs/angular-lightbox), Vue: [/docs/vue-lightbox](/docs/vue-lightbox) - Stories Player — React: [/docs/stories-player](/docs/stories-player), Angular: [/docs/angular-stories-player](/docs/angular-stories-player), Vue: [/docs/vue-stories-player](/docs/vue-stories-player) ### Installation URL: https://reelkit.dev/docs/installation # Installation Install reelkit packages + configure project. Each package version independent — install only what use. ## Package Options | Package | Description | Use Case | | ------------------------------- | -------------------------------- | ------------------------------------ | | `@reelkit/core` | Framework-agnostic core | Custom integrations | | `@reelkit/react` | React components | React 18+ applications | | `@reelkit/react-reel-player` | Full-screen vertical reel player | Instagram/TikTok style player | | `@reelkit/react-lightbox` | Image gallery lightbox | Full-screen image preview | | `@reelkit/react-stories-player` | Instagram-style stories player | Stories with auto-advance + gestures | | `@reelkit/angular` | Angular standalone components | Angular 17+ applications | | `@reelkit/angular-reel-player` | Full-screen vertical reel player | Instagram/TikTok style player | | `@reelkit/angular-lightbox` | Image gallery lightbox | Full-screen image preview | | `@reelkit/vue` | Vue 3 components and composables | Vue 3 applications | | `@reelkit/vue-reel-player` | Full-screen vertical reel player | Instagram/TikTok style player | | `@reelkit/vue-lightbox` | Image gallery lightbox | Full-screen image preview | ## Install Commands ### React ```bash npm install @reelkit/react yarn add @reelkit/react pnpm add @reelkit/react ``` ### Angular ```bash npm install @reelkit/angular yarn add @reelkit/angular pnpm add @reelkit/angular ``` ### Vue ```bash npm install @reelkit/vue yarn add @reelkit/vue pnpm add @reelkit/vue ``` ## Peer Dependencies ### React `@reelkit/react`: - `react` >= 18.0.0 - `react-dom` >= 18.0.0 `@reelkit/react-reel-player`: - `@reelkit/react` - `react` >= 18.0.0 - `react-dom` >= 18.0.0 - `lucide-react` >= 0.400.0 `@reelkit/react-lightbox`: - `@reelkit/react` - `react` >= 18.0.0 - `react-dom` >= 18.0.0 - `lucide-react` >= 0.400.0 `@reelkit/react-stories-player`: - `@reelkit/react` - `react` >= 18.0.0 - `react-dom` >= 18.0.0 - `lucide-react` >= 0.400.0 `lucide-react` only needed for default control icons. Supply own controls via `renderControls` = skip install. ### Angular `@reelkit/angular`: - `@angular/core` >= 17.0.0 - `@angular/common` >= 17.0.0 `@reelkit/angular-reel-player`: - `@reelkit/angular` - `@angular/core` >= 19.0.0 - `lucide-angular` >= 0.460.0 `@reelkit/angular-lightbox`: - `@reelkit/angular` - `@angular/core` >= 17.0.0 - `lucide-angular` >= 0.400.0 `lucide-angular` only needed for default control icons. Supply own controls via `rkPlayerControls` = skip install. ### Vue `@reelkit/vue`: - `vue` >= 3.0.0 ## TypeScript All packages ship TypeScript types. No `@types` packages needed. ## Browser Support reelkit support all modern browsers: - Chrome/Edge 88+ - Firefox 78+ - Safari 14+ - iOS Safari 14+ - Android Chrome 88+ ### Server-Side Rendering URL: https://reelkit.dev/docs/ssr # Server-Side Rendering All reelkit packages work on server. Import + render with Next.js, Remix, Angular Universal, Nuxt 3, any SSR setup. ## How It Works Core slider controller pure logic — no DOM access at construction. Gesture, keyboard, wheel listeners attach only in client lifecycle hooks. During SSR, `Reel` renders static container with initial visible slides (typically 3: prev, current, next). On hydration, attaches gesture/keyboard/wheel controllers → interactive. ### SSR Safety Matrix | Package | SSR Safe | Notes | | ------------------------------- | -------- | ------------------------------------------------------------ | | `@reelkit/core` | yes | Pure logic, no browser APIs at import or construction | | `@reelkit/react` | yes | `Reel` and `ReelIndicator` render valid HTML on server | | `@reelkit/react-reel-player` | yes | Renders nothing when `isOpen=false` | | `@reelkit/react-lightbox` | yes | Renders nothing when `isOpen=false` | | `@reelkit/react-stories-player` | yes | Renders nothing when `isOpen=false` | | `@reelkit/angular` | yes | Standalone components, SSR compatible with Angular Universal | | `@reelkit/angular-reel-player` | yes | Renders nothing when `isOpen=false` | | `@reelkit/angular-lightbox` | yes | Renders nothing when `isOpen=false` | | `@reelkit/vue` | yes | Components and composables, SSR compatible with Nuxt 3 | | `@reelkit/stories-core` | yes | Framework-agnostic, no DOM access | ## React ### Next.js App Router `Reel` use browser events + refs → Client Component. Add `"use client"` at top: ```tsx 'use client'; import { Reel, ReelIndicator } from '@reelkit/react'; export function Feed({ items }: { items: FeedItem[] }) { return ( (
{items[index].title}
)} >
); } ``` Fetch data in Server Component, pass down: ```tsx // app/feed/page.tsx (Server Component) import { Feed } from './Feed'; export default async function FeedPage() { const items = await fetchFeedItems(); return ; } ``` ### Next.js Pages Router Works no extra config. Renders during SSR, hydrates on client: ```tsx // pages/feed.tsx import { Reel } from '@reelkit/react'; import type { GetServerSideProps } from 'next'; interface Props { items: FeedItem[]; } export const getServerSideProps: GetServerSideProps = async () => { const items = await fetchFeedItems(); return { props: { items } }; }; export default function FeedPage({ items }: Props) { return ( } /> ); } ``` ### Responsive Size with SSR (React) Omit `size` prop. When not provided, `Reel` auto-measures container via `ResizeObserver` on client. SSR renders empty container; hydration measures + renders slides immediately: ```tsx 'use client'; import { Reel } from '@reelkit/react'; export function FullScreenFeed({ items }: { items: FeedItem[] }) { return ( } /> ); } ``` When `size` omitted, container ! sized by CSS (parent flex/grid, explicit width/height, or percentages). Slider renders nothing until first measurement, then fills measured dimensions + responds to resizes auto. #### Explicit size (manual approach) For pixel control, pass explicit `size`. Since `window.innerWidth` no available during SSR, provide default + update on mount: ```tsx 'use client'; import { useState, useEffect } from 'react'; import { Reel } from '@reelkit/react'; // Default size for SSR — matches common mobile viewport const DEFAULT_SIZE: [number, number] = [390, 844]; export function FullScreenFeed({ items }: { items: FeedItem[] }) { const [size, setSize] = useState<[number, number]>(DEFAULT_SIZE); useEffect(() => { const update = () => setSize([window.innerWidth, window.innerHeight]); update(); window.addEventListener('resize', update); return () => window.removeEventListener('resize', update); }, []); return ( } /> ); } ``` ### Overlay Components (React) `ReelPlayerOverlay` + `LightboxOverlay` render nothing when `isOpen={false}` → SSR-safe by default. Mount portal only when opened (typically from user interaction on client): ```tsx 'use client'; import { useState } from 'react'; import { ReelPlayerOverlay } from '@reelkit/react-reel-player'; export function VideoFeed({ content }: { content: ContentItem[] }) { const [isOpen, setIsOpen] = useState(false); const [startIndex, setStartIndex] = useState(0); return ( <>
{content.map((item, i) => ( ))}
setIsOpen(false)} content={content} initialIndex={startIndex} /> ); } ``` ## Angular ### Angular Universal / SSR All Angular components SSR-safe. Slider controller defers browser API access to `afterRenderEffect`. Overlay components render nothing when `isOpen=false` → no markup during server render. ```typescript import { Component, signal } from '@angular/core'; import { RkReelPlayerOverlayComponent } from '@reelkit/angular-reel-player'; @Component({ selector: 'app-feed', standalone: true, imports: [RkReelPlayerOverlayComponent], template: ` `, }) export class FeedComponent { isOpen = signal(false); content = [ /* ... */ ]; } ``` ## Vue ### Nuxt 3 ReelKit Vue works with Nuxt 3 out of box. `Reel` use browser APIs (touch events, ResizeObserver) → wrap in `` or use `.client.vue` suffix: ```vue ``` Feed uses Reel normally: ```vue ``` ### Responsive Size with SSR (Vue) Omit `size` for auto-measurement. Reel auto-sizes to 100% of parent. SSR renders empty container; hydration measures + renders slides: ```vue ``` ## Using Core Directly When using `@reelkit/core` direct for custom framework integration, create controller on server. Call `attach()` + `observe()` on client: ```typescript import { createSliderController } from '@reelkit/core'; // Safe to call on the server — no DOM access const controller = createSliderController({ count: 10, direction: 'vertical', }); // Only call on the client — attaches DOM event listeners if (typeof window !== 'undefined') { controller.attach(element); controller.observe(); } ``` ## Summary > [!SUCCESS] > Works out of box: > > - Import any reelkit package on server > - Render slider components during SSR (valid static HTML) > - Create controllers on server > - Overlay components when `isOpen=false` > [!WARNING] > Keep in mind: > > - Omit `size` for auto-measurement, or provide default when using viewport-based dimensions > - Don't call `attach()` / `observe()` on server when using core direct ## Core ### Core Guide URL: https://reelkit.dev/docs/core/guide # Core Guide `@reelkit/core` = framework-agnostic slider logic. Build custom integrations or understand architecture. ## Architecture Overview Core use **controller pattern** with factory functions. No classes — all plain objects from closures. Zero deps. Core coordinates: - **SliderController** — central state + navigation - **GestureController** — touch/pointer drag - **KeyboardController** — arrow keys + Escape - **WheelController** — mouse wheel, debounced ## createSliderController Make new slider controller instance. Manages all slider state + behavior. ```typescript import { createSliderController } from '@reelkit/core'; const controller = createSliderController( { count: 10, direction: 'vertical', enableWheel: true, transitionDuration: 300, }, { onAfterChange: (index) => console.log('Changed to:', index), }, ); // Attach to DOM element controller.attach(element); controller.observe(); ``` ## Controller Methods ### Navigation ```typescript // Go to specific index controller.goTo(5); // instant controller.goTo(5, true); // animated, returns Promise // Navigate to next/previous controller.next(); controller.prev(); ``` ### Lifecycle ```typescript // Connect to DOM element controller.attach(element); // Start gesture, keyboard, and wheel observation controller.observe(); // Stop gesture, keyboard, and wheel observation controller.unobserve(); // Detach DOM listeners (reversible — use for React effect cleanup) controller.detach(); // Permanent teardown (use for Angular onDestroy) controller.dispose(); // Recalculate positions controller.adjust(); // Update size controller.setPrimarySize(600); ``` ### State Updates ```typescript // Update configuration controller.updateConfig({ count: 20, loop: true, }); ``` ## Virtualization Core render only **3 slides to DOM** at any time (current, previous, next). Range extractor pick which indices in rendered window: ```typescript import { defaultRangeExtractor } from '@reelkit/core'; // Default: renders current ± 1 (3 DOM nodes) const indexes = defaultRangeExtractor(currentIndex, count); // Custom: skip hidden slides by shifting to next valid index const hiddenSlides = new Set([2, 5]); const skipHiddenExtractor = (current: number, count: number) => { const result: number[] = []; // Collect prev, current, next — skip hidden, shift forward for (let i = current - 1, added = 0; added < 3 && i < count; i++) { if (i >= 0 && !hiddenSlides.has(i)) { result.push(i); added++; } } return result; }; ``` Result always clamped max 3 indices. If extractor return more, core keep 3 centered on current slide. ## Signals Core use lightweight signal system for reactivity: ```typescript import { createSignal, createComputed, reaction } from '@reelkit/core'; // Create a signal const count = createSignal(0); // Observe changes (returns a disposer function) const dispose = count.observe(() => console.log(count.value)); // Update value count.value = 5; // Create computed signal (requires a deps factory) const doubled = createComputed( () => count.value * 2, () => [count], ); // Run side effects on signal changes const disposeReaction = reaction( () => [count], () => console.log('Count changed:', count.value), ); // Cleanup dispose(); disposeReaction(); ``` ## Controller State Reach reactive state via `controller.state`: ```typescript const { index, axisValue, indexes } = controller.state; // Observe index changes (returns a disposer function) const disposeIndex = index.observe(() => { console.log('Current index:', index.value); }); // Observe visible indexes for virtualization const disposeIndexes = indexes.observe(() => { console.log('Visible:', indexes.value); }); // Cleanup when done disposeIndex(); disposeIndexes(); ``` ## Timeline Controller Build custom scrub bar for any `