Skip to main content

Overview

Live interactive component embed for showcasing React components within slides. Keyboard navigation (arrow keys, space) is disabled while focus is inside the demo area so the embedded component can handle its own input. The container tracks its maximum height to prevent layout jumps when the child re-renders with different content sizes.

Props

children
React.ReactNode
required
The interactive React component(s) to embed in the demo area.
label
string
Optional uppercase label shown above the demo area.
className
string
Additional CSS classes to apply to the wrapper element.

Usage Examples

Basic Demo

<SlideDemo label="Live counter">
  <Counter />
</SlideDemo>

Form Component

<Slide>
  <SlideTitle>Interactive Form</SlideTitle>
  <SlideDemo label="Try it out">
    <LoginForm />
  </SlideDemo>
</Slide>

Multiple Components

<SlideDemo label="Component showcase">
  <div className="flex gap-4">
    <Button>Click me</Button>
    <Button variant="outline">Secondary</Button>
  </div>
</SlideDemo>

Without Label

<SlideDemo>
  <InteractiveChart data={chartData} />
</SlideDemo>

Custom Styling

<SlideDemo 
  label="Full width demo"
  className="max-w-4xl"
>
  <Dashboard />
</SlideDemo>

In Two-Column Layout

<Slide>
  <SlideTitle>Live Demo</SlideTitle>
  <SlideColumns
    left={
      <SlideCode title="Counter.tsx">{`export function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}`}</SlideCode>
    }
    right={
      <SlideDemo label="Result">
        <Counter />
      </SlideDemo>
    }
  />
</Slide>

Keyboard Navigation

Interactive Mode

The demo area has a data-slide-interactive attribute that signals to the slide deck to disable keyboard navigation while focus is inside. This allows embedded components to:
  • Use arrow keys for their own navigation
  • Handle space bar for interactions (checkboxes, buttons)
  • Prevent accidental slide transitions during interaction

Implementation Detail

The SlideDeck component checks for focus within [data-slide-interactive] elements before processing keyboard shortcuts. When focus is inside a demo area, slide navigation is temporarily disabled.

Styling Details

Container Structure

<div data-slide-interactive className="min-w-0 w-full max-w-2xl">
  {label && <div className="text-muted-foreground mb-2 text-sm font-medium tracking-wider uppercase">{label}</div>}
  <div className="border-foreground/10 bg-foreground/[0.03] min-w-0 w-full max-w-full border p-4 sm:p-6">
    <SlideDemoContent>{children}</SlideDemoContent>
  </div>
</div>

Default Styles

  • Wrapper: max-w-2xl width constraint, full width on smaller screens
  • Label: Muted color, small text, uppercase with letter spacing
  • Demo area: Light background (bg-foreground/[0.03]), subtle border, responsive padding (p-4p-6)

Height Tracking

The internal SlideDemoContent component uses a ref and effect to track the maximum height of the demo content, preventing layout shifts when content changes size:
// Internal implementation (from slide-demo-content.tsx)
const maxHeight = useRef(0);
const contentRef = useRef<HTMLDivElement>(null);

useEffect(() => {
  if (contentRef.current) {
    const currentHeight = contentRef.current.offsetHeight;
    if (currentHeight > maxHeight.current) {
      maxHeight.current = currentHeight;
    }
  }
});

Best Practices

State Management

Components inside SlideDemo maintain their state during slide transitions. For demos that should reset on each visit:
function ResetOnVisit() {
  const [key, setKey] = useState(0);
  
  useEffect(() => {
    // Reset demo when slide becomes active
    setKey(prev => prev + 1);
  }, [/* slide visibility */]);
  
  return (
    <SlideDemo>
      <MyComponent key={key} />
    </SlideDemo>
  );
}

Performance

For complex interactive demos, consider lazy loading:
const HeavyComponent = lazy(() => import('./HeavyComponent'));

<SlideDemo label="Performance demo">
  <Suspense fallback={<div>Loading...</div>}>
    <HeavyComponent />
  </Suspense>
</SlideDemo>

Accessibility

Ensure embedded components are keyboard accessible:
<SlideDemo label="Accessible form">
  <form>
    <label htmlFor="name">Name:</label>
    <input id="name" type="text" />
    <button type="submit">Submit</button>
  </form>
</SlideDemo>

Build docs developers (and LLMs) love