Skip to main content
@capgo/capacitor-transitions UI & System Open source

Transitions Capacitor plugin

Add Ionic-style page transitions and iOS edge swipe-back gestures without Ionic UI

Install

bun add @capgo/capacitor-transitions bunx cap sync
npm, pnpm or yarn
  • npm install @capgo/capacitor-transitions
  • pnpm add @capgo/capacitor-transitions
  • yarn add @capgo/capacitor-transitions

Demo

Transitions demos

A React router flow showing iOS-style Capacitor page transitions as an animated WebP demo.

Source assets
Animated React page transition demo showing forward and back navigation in a Capacitor-style shell
React transition flow

Guide

How to use Transitions in Capacitor

Test on device

Download the Capgo app, then scan the QR code.

Transitions plugin preview QR code

Using @capgo/capacitor-transitions

@capgo/capacitor-transitions adds Ionic-style route transitions to Capacitor apps without adopting Ionic UI. It runs in the web layer, keeps your existing router, and can auto-enable an iOS edge swipe-back gesture only inside native Capacitor iOS.

Install

npm install @capgo/capacitor-transitions

There is no native sync step because the package does not add native plugin code.

Register the elements

import '@capgo/capacitor-transitions';

Wrap your 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>

Connect it to a router

Set the transition direction before your normal route update:

import { setDirection } from '@capgo/capacitor-transitions/react';

setDirection('forward');
router.push('/message/42');

setDirection('back');
router.back();

React example

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}>{/* routes */}</cap-router-outlet>;
}

export function InboxPage() {
  const navigate = useNavigate();
  const pageRef = useRef<HTMLElement>(null);

  useEffect(() => {
    if (!pageRef.current) return;
    return setupPage(pageRef.current);
  }, []);

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

The React subpath includes JSX typings for the custom elements. If TypeScript still reports that cap-router-outlet does not exist on JSX.IntrinsicElements, add this file:

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

For Vite, Create React App, and most webpack React apps, keeping that file under src/ is enough. For Next.js or custom TypeScript setups, make sure it is included by tsconfig.json:

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

Enable swipe back

Use swipe-gesture="auto" to enable the gesture only when Capacitor reports a native iOS runtime:

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

You can also force it from JavaScript:

const outlet = document.querySelector('cap-router-outlet');

outlet?.setSwipeGesture(true);
outlet?.setSwipeGesture(false);
outlet?.setSwipeGesture('auto');

The gesture follows the finger during the transition, then completes or cancels when the user releases. Add data-swipe-gesture-ignore on buttons, sliders, or drawers that should not start the edge gesture.

Use with native navigation

Install @capgo/native-navigation when the native layer should own the navbar or tabbar:

npm install @capgo/native-navigation
npx cap sync

Configure native chrome, then keep transitions focused on the WebView pages:

import { NativeNavigation } from '@capgo/native-navigation';
import { setDirection } from '@capgo/capacitor-transitions/react';
import { router } from './router';

await NativeNavigation.configure({
  contentInsetMode: 'css',
});

await NativeNavigation.setNavbar({
  title: 'Inbox',
  backButton: { visible: false },
});

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

Use cap-content for the animated page body and native-navigation CSS variables for insets:

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

Do not duplicate the native navbar as a moving web header. @capgo/native-navigation keeps the bar native; @capgo/capacitor-transitions animates the page content underneath it.

Full Reference

Keep going from Using @capgo/capacitor-transitions

If you are using Using @capgo/capacitor-transitions to plan native media and interface behavior, connect it with @capgo/capacitor-transitions for the implementation detail in @capgo/capacitor-transitions, Getting Started for the implementation detail in Getting Started, Using @capgo/capacitor-live-activities for the native capability in Using @capgo/capacitor-live-activities, @capgo/capacitor-live-activities for the implementation detail in @capgo/capacitor-live-activities, and Using @capgo/capacitor-video-player for the native capability in Using @capgo/capacitor-video-player.

FAQ

Transitions plugin FAQ

How do I install the Transitions plugin in a Capacitor app?

Run "bun add @capgo/capacitor-transitions" (or "npm install @capgo/capacitor-transitions"), then run "bunx cap sync" so the iOS and Android projects pick up the native code. Import it from "@capgo/capacitor-transitions" in your app code.

Does @capgo/capacitor-transitions work with React, Vue and Angular?

Yes. Transitions is a Capacitor package, so it works with any web framework that runs inside Capacitor, including Ionic, React, Vue, Angular, Svelte and plain JavaScript.

Which Capacitor version does @capgo/capacitor-transitions support?

Capgo plugins follow Capacitor's major version: use the plugin major version that matches your Capacitor major version (for example plugin v8 with Capacitor 8). The compatibility table in the GitHub README lists the maintained versions.

Is @capgo/capacitor-transitions free and open source?

Yes. The source code is public on GitHub at https://github.com/Cap-go/capacitor-transitions/ and the package is free to install from npm. Bug reports and pull requests are welcome.

Can I update code that uses Transitions without an App Store review?

Installing or upgrading the plugin changes native code, so it needs a new store build. After that, JavaScript, HTML and CSS changes that call the plugin can ship instantly with Capgo live updates.

Ship Transitions changes without waiting for app review

Once the plugin is in your store build, Capgo live updates push your JavaScript, HTML and CSS changes to users in minutes.

Start with Capgo