API Reference

The v2 persistent-layer API for SectionFlow transitions.

<SectionFlow>

The root stage component. Groups consecutive <Section> children into transition spans (pinned viewports) and flow sections (native browser scroll).

import { SectionFlow, Section } from '@/components/sectionflow/core/section-flow';
PropTypeDefaultDescription
childrenReactNoderequired<Section> elements.
heightPerSectionnumber200Scroll distance (vh) for each transition's animation window. Longer = slower transition.
restHeightnumber100Global default for the viewing phase (vh) — reading window before animation begins.
defaultTransitionTransitionComponent | stringFallback transition for sections that omit one.
classNamestringExtra classes for the wrapper.

<Section>

A marker component. Carries content and an optional outgoing transition declaration. Sections are mounted once as persistent layers when inside a transition span, or as plain <section> elements for native scroll.

<Section transition={CardStack}>
  <div className="h-full w-full">Your content</div>
</Section>
PropTypeDefaultDescription
childrenReactNoderequiredSection content.
transitionTransitionComponent | stringOutgoing transition — the handoff from this section to the next. Omit for native scroll.
classNamestringExtra classes on the section shell.

TransitionProps

Every v2 transition component receives these props:

interface TransitionProps {
  /** Local 0→1 progress across this edge's animation window. */
  progress: MotionValue<number>;
  /** Scroll direction across the edge. */
  direction: TransitionDirection;
  /** Pinned viewport size. */
  viewport: Viewport;
  /** Handle to the outgoing (current) layer. */
  outgoing: LayerHandle;
  /** Handle to the incoming (next) layer. */
  incoming: LayerHandle;
}

LayerHandle

A handle to a once-mounted section layer. Transitions write motion values into the style bag, which the stage spreads onto the real layer element:

interface LayerHandle {
  /** Bag of MotionValues the transition writes. */
  style: MotionStyle;
  /** Measured bounds of the layer. */
  bounds: LayerBounds;
  /** Optional renderer for transitions that need real content clones. */
  render?: () => ReactElement;
}

TransitionComponent

A transition is a component that receives TransitionProps and optionally declares static timing and copies fields:

export function MyTransition({ progress, outgoing, incoming }: TransitionProps) {
  const opacity = useTransform(progress, [0, 1], [1, 0]);
  outgoing.style.opacity = opacity;
  return null;
}

// Optional: override viewing-phase and animation-window duration (in vh)
MyTransition.timing = { rest: 120, duration: 250 };

// Optional: opt in to content cloning so the transition can render real copies
MyTransition.copies = true;

The timing field lets a transition control how much scroll is allotted to its reading window (rest) and animation window (duration), overriding the stage's restHeight and heightPerSection defaults for that edge only. When copies is true, the stage exposes a render() method on each layer handle so the transition can produce real visual copies of the section content.

transitionRegistry

Maps string slugs to transition components:

import { transitionRegistry } from '@/components/sectionflow/core/registry';

// Use in Section:
<Section transition="card-stack">...</Section>

// Resolve programmatically:
const Component = transitionRegistry['card-stack'];

resolveTransition(resolver)

Resolves a TransitionResolver (string slug or component) to a TransitionComponent | null:

import { resolveTransition } from '@/components/sectionflow/core/registry';

const component = resolveTransition('circular-portal'); // TransitionComponent | null
const component2 = resolveTransition(CircularPortal);  // TransitionComponent | null

Transition shapes

V2 transitions fall into three common patterns:

Mask reveal

Writes a clip-path or mask onto the incoming layer:

const clipPath = useMotionTemplate`circle(${radius}% at 50% 50%)`;
incoming.style.clipPath = clipPath;

Layer choreography

Writes transforms onto both layers directly:

outgoing.style.scale = outScale;
incoming.style.y = y;

Effect overlay

Returns overlay elements (SVG, particles, shards) positioned above the layers:

return (
  <>
    <motion.div aria-hidden style={{ ... }} className="absolute inset-0 z-20">
      {/* Overlay content */}
    </motion.div>
  </>
);

Exported types

export type {
  TransitionComponent,
  TransitionResolver,
  TransitionProps,
  LayerHandle,
  LayerBounds,
  Viewport,
  TransitionDirection,
  TransitionTiming,
  SectionProps,
  SectionFlowProps,
};