SSGOI

hero

Hero preserves the identity of matching elements across two pages while the surrounding surfaces change.

Drill-in — List → detail, going one level deeper.

When this motion fits

When to use
Use it when a thumbnail, avatar, or other stable entity appears on both pages and should visibly continue.
What moves
Each matched element morphs from its source bounds into its destination bounds; multiple distinct pairs can move together.
Avoid when
Avoid it when there is no stable shared identity. If one card should open into the whole page, Zoom is usually clearer.

Add it to a route rule

hero() sets the motion; the rule around it decides which navigations get it. The config shape is the same in every framework.

import { hero } from "@ssgoi/react/view-transitions";

const config = {
  transitions: [
    {
      from: "/list",
      to: "/detail/*",
      transition: hero(),
    },
  ],
};

Pattern forms, priority and the scroll defaults that come with each rule shape are on Route rules.

Connect the source to the destination

The attribute value is the element's stable identity. Source and destination values must match exactly.

PageAttribute on the element
Source pagedata-hero-exit-key="same-id"
Destination pagedata-hero-enter-key="same-id"
  • You may mark multiple distinct key pairs; Hero animates every pair it can match.
  • Keep each identity unique on a page. If a key is duplicated, the first element in DOM order is used.
  • Pairs without a matching key on the other page are skipped.
With no matching pairs, Hero has no shared element to animate and becomes a no-op.
{/* Source: list or collapsed page */}
<img
  data-hero-exit-key={item.id}
  src={item.thumbnail}
  alt={item.alt}
/>

{/* Destination: detail or expanded page */}
<img
  data-hero-enter-key={item.id}
  src={item.full}
  alt={item.alt}
/>

Configurations

type, variant and option are independent. Each clip is recorded from a demo published on ssgoi.dev. Combinations without a published demo keep the API details without a substitute clip.

  • static · default

    type: staticvariant: defaultdefault

    The surrounding pages switch without a surface fade while the shared element continues between them.

    hero({ type: "static" })
  • fade · default

    type: fadevariant: default

    The surrounding pages fade as the shared element continues, softening the hand-off.

    A photo morphs into its detail position while the surrounding pages fade.
    hero({ type: "fade" })

    Open live demoOpens at the source screen

  • static · smooth

    type: staticvariant: smooth

    Smooth changes the shared element's interpolation for a softer, more continuous morph. It is independent of the static/fade type.

    Several photo elements smoothly morph into a gallery while the page surfaces switch directly.
    hero({ type: "static", variant: "smooth" })

    Open live demoOpens at the source screen

  • fade · smooth

    type: fadevariant: smooth

    Combines the smooth shared-element interpolation with a fading page hand-off.

    hero({ type: "fade", variant: "smooth" })

Agent guide: /llms/transitions/hero.txt — every prop, the required markup, and a config fragment as plain text.

Read next