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>
);
}

Importing from @capgo/capacitor-transitions/react includes JSX typings for cap-router-outlet, cap-page, cap-header, cap-content, and cap-footer. In most React projects, that import makes the custom elements valid in TSX automatically.

If TypeScript still reports Property 'cap-router-outlet' does not exist on type 'JSX.IntrinsicElements', add a project declaration file:

src/capgo-transitions.d.ts
import '@capgo/capacitor-transitions/react';

For Vite, Create React App, and most webpack React apps, placing that file inside src/ is enough. For Next.js, put it in src/ or the project root and make sure tsconfig.json includes it:

{
"include": ["src", "src/capgo-transitions.d.ts"]
}

For custom TypeScript or webpack setups that use a separate types/ folder, include that folder instead:

{
"include": ["src", "types"]
}

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

If you are using Getting Started to plan migration and enterprise operations, connect it with Using @capgo/capacitor-transitions for the native capability in Using @capgo/capacitor-transitions, Capgo Enterprise for the product workflow in Capgo Enterprise, Ionic Enterprise Plugin Alternatives for the product workflow in Ionic Enterprise Plugin Alternatives, Capgo Alternatives for the product workflow in Capgo Alternatives, and Capgo Consulting for the product workflow in Capgo Consulting.