Skip to main content
Breakout pages live inside the slides folder but outside the [page] route. They render without deck navigation chrome — perfect for live demos, interactive examples, or fullscreen content.

Structure

Place demo pages as siblings to the [page] route:
app/slides/
  layout.tsx          ← SlideDeck provider
  [page]/page.tsx     ← Slide routes (1, 2, 3...)
  demo/page.tsx       ← Breakout page (no deck chrome)
  editor/page.tsx     ← Another breakout page
Because they’re children of the slides/layout.tsx, they inherit the SlideDeck context — but they don’t render slide navigation, progress indicators, or keyboard controls.

Why Use Breakout Pages

Live demos: Show a working component or feature without slide decorations:
app/slides/demo/page.tsx
'use client';

import { useState } from 'react';

export default function DemoPage() {
  const [count, setCount] = useState(0);

  return (
    <div className="flex min-h-screen items-center justify-center">
      <div className="text-center">
        <h1 className="text-4xl font-bold mb-8">Interactive Counter</h1>
        <p className="text-6xl mb-8">{count}</p>
        <div className="flex gap-4 justify-center">
          <button
            onClick={() => setCount(count - 1)}
            className="px-6 py-3 bg-red-500 text-white rounded-lg"
          >
            Decrement
          </button>
          <button
            onClick={() => setCount(count + 1)}
            className="px-6 py-3 bg-blue-500 text-white rounded-lg"
          >
            Increment
          </button>
        </div>
      </div>
    </div>
  );
}
Code editors: Build an interactive playground for live coding. Fullscreen media: Videos, images, or animations that need the entire viewport. Forms and surveys: Collect audience feedback during the presentation.

Linking from Slides

Use SlideLink to navigate to breakout pages:
app/slides/slides.tsx
import { Slide, SlideTitle, SlideLink } from 'nextjs-slides';

export const slides = [
  // ... other slides
  
  <Slide key="demo-link" align="left">
    <SlideTitle>Let's see it in action</SlideTitle>
    <SlideLink href="/slides/demo" variant="primary">
      Launch Demo →
    </SlideLink>
  </Slide>,
];

Returning to Slides

Add a “Back to slides” link that returns to the slide that launched the demo:
app/slides/demo/page.tsx
import Link from 'next/link';

export default function DemoPage() {
  return (
    <div className="min-h-screen p-8">
      <Link
        href="/slides/12"
        className="text-sm text-muted-foreground hover:text-foreground"
      >
        ← Back to slides
      </Link>
      
      {/* Demo content */}
    </div>
  );
}
Link back to the specific slide number that contains the demo link. This creates a seamless flow: slide → demo → same slide.

Keyboard Navigation

Breakout pages don’t have deck keyboard navigation enabled. This means:
  • Arrow keys and spacebar won’t change slides
  • You can use text inputs, contentEditable, and other interactive elements
  • Users must click links to navigate
This is the same behavior as content inside <SlideDemo> primitives on regular slides.

Example: Live Code Editor

Here’s a complete breakout page with a Monaco editor:
app/slides/editor/page.tsx
'use client';

import dynamic from 'next/dynamic';
import Link from 'next/link';
import { useState } from 'react';

const Monaco = dynamic(() => import('@monaco-editor/react'), { ssr: false });

export default function EditorPage() {
  const [code, setCode] = useState(
    `function greet(name: string) {\n  return \`Hello, \${name}!\`;\n}\n\nconsole.log(greet('World'));`
  );

  return (
    <div className="flex flex-col h-screen">
      <header className="flex items-center justify-between px-6 py-4 border-b">
        <h1 className="text-lg font-semibold">Live TypeScript Editor</h1>
        <Link
          href="/slides/15"
          className="text-sm text-muted-foreground hover:text-foreground"
        >
          ← Back to slides
        </Link>
      </header>
      
      <div className="flex-1">
        <Monaco
          height="100%"
          language="typescript"
          theme="vs-dark"
          value={code}
          onChange={(value) => setCode(value || '')}
          options={{
            minimap: { enabled: false },
            fontSize: 16,
          }}
        />
      </div>
    </div>
  );
}

Sharing Context

Breakout pages inherit the SlideDeck provider, which means they share:
  • CSS variables (colors, fonts)
  • Tailwind theme configuration
  • Any custom context providers in the layout
This ensures visual consistency between slides and demos.

Demo Notes Integration

Combine breakout pages with demo notes for guided walkthroughs:
  1. Add demo notes after your slide notes (see Speaker Notes)
  2. Link to the breakout page from the last slide
  3. Use your phone to step through demo notes while presenting the breakout page
Example notes file:
notes.md
...last slide notes

---

Open the counter demo. Click increment a few times.

---

Show the decrement button. Explain how state updates trigger re-renders.

---

Open devtools. Show React component tree.
Navigate to /slides/demo on your laptop, keep /notes open on your phone, and manually step through the demo notes.

Advanced: Nested Routes

You can create deeply nested breakout pages:
app/slides/
  layout.tsx
  [page]/page.tsx
  demos/
    counter/page.tsx
    editor/page.tsx
    chart/page.tsx
All routes under slides/ inherit the provider, no matter how deep.

Build docs developers (and LLMs) love