Events & lifecycle
SharedHero provides lifecycle callbacks and control props (enabled, returnFlightEnabled, and namespace) so you can coordinate surrounding UI elements, scope hero IDs across independent navigation trees, and handle interrupted transitions cleanly.
Lifecycle callbacks
Both callbacks receive a plain SharedHeroTransitionEvent object ({ id: string, namespace: string }) unwrapped from the native synthetic event:
| Prop | Payload (SharedHeroTransitionEvent) | When it fires |
|---|---|---|
onTransitionStart | { id: string, namespace: string } | Fired on the source view when a forward flight begins, or on the destination view when a return flight begins. |
onTransitionEnd | { id: string, namespace: string } | Fired on the destination view when a forward flight lands, or on the source view when a return flight finishes. |
import { useState } from 'react';
import { SharedHero } from 'react-native-shared-hero';
export function DetailHeader({ item }) {
const [chromeVisible, setChromeVisible] = useState(false);
return (
<>
<SharedHero
id={`photo-${item.id}`}
namespace="feed"
mode="morph"
onTransitionStart={({ id, namespace }) => {
console.log('Flight started:', namespace, id);
setChromeVisible(false);
}}
onTransitionEnd={({ id, namespace }) => {
console.log('Flight ended:', namespace, id);
setChromeVisible(true);
}}
>
<HeroImage uri={item.fullUrl} />
</SharedHero>
{chromeVisible && <FloatingActionButtons />}
</>
);
}Isolating hero registries with namespace
By default, all <SharedHero> instances share namespace="default" and are matched by the composite key namespace::id.
If your app renders the same data item across multiple independent navigation trees (for example, a Home feed tab and a Profile bookmarks tab that can both stay mounted), pass a distinct namespace to prevent cross-tab collisions:
<SharedHero id={`post-${post.id}`} namespace="bookmarks" mode="morph">
<PostThumbnail post={post} />
</SharedHero>Controlling back flights with returnFlightEnabled
By default (returnFlightEnabled={true}), unmounting a destination <SharedHero> automatically triggers a return flight back to the matching source <SharedHero>.
If your destination lives inside a container whose own dismissal animation already carries the view off-screen, you can disable only the outbound return flight while keeping the inbound flight intact:
<SharedHero
id={`modal-photo-${item.id}`}
returnFlightEnabled={false}
>
<Image source={{ uri: item.uri }} style={styles.image} />
</SharedHero>Endpoint visibility and soft handoff
While a transition for namespace::id is running:
- Both the source view and the destination view are hidden by
FlightEngine(isHidden = trueoncontentViewon iOS,alpha = 0fon Android) so you never see duplicate ghost elements underneath the flying overlay. - When the geometric flight finishes,
FlightEngineun-hides the destination endpoint first and then fades out the overlay clone over a brief soft-handoff window, eliminating single-frame flicker.
Mid-air flight takeovers
Users frequently tap Back or swipe to dismiss while the forward push flight is still in mid-air.
If a transition for id="photo-1" is currently halfway across the screen when the destination screen pops:
FlightEnginedetects that anActiveFlightfor the same key is still on screen (canTakeOver).- Instead of running two conflicting overlays or snapping to the settled destination rect,
FlightEngineinterrupts the old flight, reads the flying view's live presentation rect in window coordinates (layer.presentation()?.frameon iOS, live container bounds on Android), and starts the return flight from that exact mid-air position. - The element reverses course smoothly back into its source slot without jumping.
Conditional participation with enabled
Pass enabled={false} to temporarily take a <SharedHero> out of HeroRegistry without changing your React component tree:
<SharedHero
id={`video-${clip.id}`}
enabled={!isPictureInPictureActive}
>
<VideoPreview clip={clip} />
</SharedHero>When enabled changes from true to false on a mounted view, the native view immediately unregisters from HeroRegistry, so subsequent navigations proceed as normal screen transitions.