Server-Side Rendering
All reelkit packages work on the server. Import and render them with Next.js, Remix, Angular Universal, or any SSR setup.
How It Works
The core slider controller is pure logic with no DOM access at construction. Gesture listeners, keyboard events, and animations attach only in client-side lifecycle hooks.
During SSR, the Reel component renders a static container with the initial visible slides (typically 3: previous, current, next). On hydration, it attaches gesture, keyboard, and wheel controllers to make everything interactive.
| 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 the server |
| @reelkit/angular | Yes | Standalone components, SSR compatible with Angular Universal |
| @reelkit/vue | Yes | Components and composables, SSR compatible with Nuxt 3 |
| @reelkit/react-reel-player | Yes | Renders nothing when closed (isOpen=false) |
| @reelkit/react-lightbox | Yes | Renders nothing when closed (isOpen=false) |
| @reelkit/angular-reel-player | Yes | Renders nothing when closed (isOpen=false) |
| @reelkit/angular-lightbox | Yes | Renders nothing when closed (isOpen=false) |
| @reelkit/stories-core | Yes | Framework-agnostic, no DOM access |
| @reelkit/react-stories-player | Yes | Renders nothing when closed (isOpen=false) |
Next.js App Router
Reel uses browser events and refs, so it runs as a Client Component. Add the "use client" directive at the top of the file that uses Reel:
You can fetch data in a Server Component and pass it down:
Next.js Pages Router
Pages Router works without extra configuration. The component renders during SSR and hydrates on the client:
Responsive Size with SSR
Omit the size prop entirely. When size is not provided, Reel auto-measures its container via ResizeObserver on the client. During SSR the slider renders an empty container; on hydration it measures and renders slides immediately:
How auto-size works
When size is omitted, the container must be sized by CSS (parent flex/grid, explicit width/height, or percentages). The slider renders nothing until the first measurement completes, then fills the measured dimensions and responds to subsequent resizes automatically.
Explicit size (manual approach)
For pixel-level control, pass an explicit size prop. Since window.innerWidth is not available during SSR, provide a default and update on mount:
Tip
Choose a default size that matches your most common viewport (e.g. mobile-first). The slider will re-adjust instantly on hydration if the actual viewport differs.
Overlay Components
ReelPlayerOverlay and LightboxOverlay render nothing when isOpen={false}, so they are SSR-safe by default. They only mount their portal when opened (typically from a user interaction on the client):
Angular Universal / SSR
All Angular components are SSR-safe. The slider controller defers browser API access to afterRenderEffect. Overlay components render nothing when isOpen=false, so they produce no markup during server rendering.
Nuxt 3
ReelKit Vue components work with Nuxt 3 out of the box. Since Reel uses browser APIs (touch events, ResizeObserver), wrap it in a <ClientOnly> component or use .client.vue suffix:
The Feed component uses Reel normally:
Responsive Size with SSR
Omit the size prop to use auto-measurement. The Reel auto-sizes to 100% of its parent. During SSR it renders an empty container; on hydration it measures and renders slides:
Using Core Directly
When using @reelkit/core directly for a custom framework integration, you can create the controller on the server. Call attach() and observe() on the client:
Summary
What works out of the box
- Importing any reelkit package on the server
- Rendering slider components during SSR (produces valid static HTML)
- Creating controllers on the server
- Overlay components when
isOpen=false
What to keep in mind
- Omit
sizefor auto-measurement, or provide a default when using viewport-based dimensions - Don't call
attach()/observe()on the server when using core directly