Skip to content

Getting Started

  1. Install the package

    Terminal window
    npm install @capgo/capacitor-transitions
  2. Register the web components

    import '@capgo/capacitor-transitions';
  3. Wrap routed pages

    <cap-router-outlet platform="auto" swipe-gesture="auto">
    <cap-page>
    <cap-header slot="header">
    <h1>Inbox</h1>
    </cap-header>
    <cap-content slot="content">
    <button>Open message</button>
    </cap-content>
    <cap-footer slot="footer">
    <nav>Tabs</nav>
    </cap-footer>
    </cap-page>
    </cap-router-outlet>
  4. Set the direction before your router changes route

    import { setDirection } from '@capgo/capacitor-transitions/react';
    setDirection('forward');
    router.push('/message/42');
    setDirection('back');
    router.back();
import { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { initTransitions, setDirection, setupPage, setupRouterOutlet } from '@capgo/capacitor-transitions/react';
import '@capgo/capacitor-transitions';
initTransitions({ platform: 'auto' });
export function AppShell() {
const outletRef = useRef<HTMLElement>(null);
useEffect(() => {
if (!outletRef.current) return;
setupRouterOutlet(outletRef.current, {
platform: 'auto',
swipeGesture: 'auto',
});
}, []);
return (
<cap-router-outlet ref={outletRef}>
{/* Your router renders cap-page children here. */}
</cap-router-outlet>
);
}
export function InboxPage() {
const navigate = useNavigate();
const pageRef = useRef<HTMLElement>(null);
useEffect(() => {
if (!pageRef.current) return;
return setupPage(pageRef.current, {
onDidEnter: () => console.log('Inbox visible'),
});
}, []);
return (
<cap-page ref={pageRef}>
<cap-header slot="header">
<h1>Inbox</h1>
</cap-header>
<cap-content slot="content">
<button
onClick={() => {
setDirection('forward');
navigate('/message/42');
}}
>
Open message
</button>
</cap-content>
</cap-page>
);
}

Enable or disable the iOS edge gesture from markup:

<cap-router-outlet swipe-gesture="auto"></cap-router-outlet>
<cap-router-outlet swipe-gesture="true"></cap-router-outlet>
<cap-router-outlet swipe-gesture="false"></cap-router-outlet>

Or from JavaScript:

const outlet = document.querySelector('cap-router-outlet');
outlet?.setSwipeGesture('auto');
outlet?.setSwipeGesture(true);
outlet?.setSwipeGesture(false);

auto enables the gesture only when Capacitor reports a native iOS runtime. During the gesture, the page transition follows the finger. When the user releases, the transition either completes and asks the browser history to go back, or cancels and restores the current page.

To keep an element from starting the gesture, add data-swipe-gesture-ignore:

<button data-swipe-gesture-ignore>Open drawer</button>

Use @capgo/capacitor-transitions with @capgo/native-navigation when native should own the top and bottom bars while web content keeps Ionic-style page motion.

  1. Install and sync the native navigation package:

    Terminal window
    npm install @capgo/native-navigation
    npx cap sync
  2. Configure native chrome:

    import { NativeNavigation } from '@capgo/native-navigation';
    await NativeNavigation.configure({
    contentInsetMode: 'css',
    });
    await NativeNavigation.setNavbar({
    title: 'Inbox',
    backButton: { visible: false },
    });
  3. Keep the web transition outlet responsible for pages only:

    <cap-router-outlet platform="auto" swipe-gesture="auto">
    <cap-page>
    <cap-content slot="content" fullscreen>
    <main class="native-page">Inbox content</main>
    </cap-content>
    </cap-page>
    </cap-router-outlet>
    .native-page {
    padding-top: var(--cap-native-navigation-top);
    padding-bottom: var(--cap-native-navigation-bottom);
    }
  4. Drive both systems from the same router events:

    import { NativeNavigation } from '@capgo/native-navigation';
    import { setDirection } from '@capgo/capacitor-transitions/react';
    import { router } from './router';
    await NativeNavigation.addListener('navbarBack', () => {
    setDirection('back');
    router.back();
    });
    async function openMessage(id: string) {
    setDirection('forward');
    router.push(`/message/${id}`);
    await NativeNavigation.setNavbar({
    title: 'Message',
    backButton: { visible: true, title: 'Inbox' },
    });
    }

Do not render the native top bar again as a moving <cap-header>. Let @capgo/native-navigation keep the bar native and use @capgo/capacitor-transitions for the WebView page content underneath it.

AttributeTypeDefaultDescription
platform'ios' | 'android' | 'auto''auto'Animation style
durationnumberPlatform defaultAnimation duration in milliseconds
keep-in-dombooleantrueKeep inactive pages in the DOM
max-cachednumber10Maximum cached pages
swipe-gestureboolean | 'auto''auto'Enable, disable, or native-detect the iOS edge gesture

Methods:

  • push(element, config?)
  • pop(config?)
  • setRoot(element, config?)
  • setSwipeGesture(true | false | 'auto')

Wraps one page and emits lifecycle events:

  • cap-will-enter
  • cap-did-enter
  • cap-will-leave
  • cap-did-leave
AttributeTypeDefaultDescription
fullscreenbooleanfalseLet content scroll behind the header
scroll-xbooleantrueEnable horizontal scrolling
scroll-ybooleantrueEnable vertical scrolling

The framework entrypoints expose the same core helpers:

import { initTransitions, setDirection, setupPage, setupRouterOutlet } from '@capgo/capacitor-transitions/react';
initTransitions({ platform: 'auto' });
setDirection('forward');
setupRouterOutlet(element, { platform: 'auto', swipeGesture: 'auto' });
setupPage(element, { onWillEnter, onDidEnter, onWillLeave, onDidLeave });

Available entrypoints:

  • @capgo/capacitor-transitions/react
  • @capgo/capacitor-transitions/vue
  • @capgo/capacitor-transitions/angular
  • @capgo/capacitor-transitions/svelte
  • @capgo/capacitor-transitions/solid