Capstart

Transitions

Add framework-agnostic page transitions to a Capacitor app.

@capgo/transitions adds native-feeling page transitions to a Capacitor app without forcing a design system or a router.

It is a separate library from @capgo/capacitor-native-navigation. You can use both together: Native Navigation can render the native navbar and tabbar, while Transitions animates the page content underneath.

Demo

What It Does

  • Adds iOS-style and Android-style page animations.
  • Works with React, Vue, Angular, Svelte, Solid, vanilla JavaScript, and other web frameworks.
  • Uses the Web Animations API for smooth browser animations.
  • Can use the View Transitions API when the browser supports it.
  • Keeps pages in the DOM for fast back navigation.
  • Coordinates header, content, and footer transitions.
  • Exposes lifecycle hooks such as enter and leave events.

What It Does Not Replace

  • It does not replace your router.
  • It does not provide a UI kit or CSS design system.
  • It does not render native bars by itself.
  • It does not require Ionic.

Installation

npm install @capgo/transitions

The package is published as @capgo/transitions. The GitHub repository is named capacitor-transitions.

Basic Structure

Use a cap-router-outlet as the transition container. Each screen is a cap-page with optional header, content, and footer slots.

page.html
<cap-router-outlet platform="auto">
  <cap-page>
    <cap-header slot="header">
      <h1>Home</h1>
    </cap-header>

    <cap-content slot="content">
      <p>Page content here</p>
    </cap-content>

    <cap-footer slot="footer">
      <nav>Tab bar</nav>
    </cap-footer>
  </cap-page>
</cap-router-outlet>

React Setup

Initialize transitions once, connect your router outlet, then set the direction before route changes.

App.tsx
import { useEffect, useRef } from 'react';
import {
  initTransitions,
  setupRouterOutlet,
} from '@capgo/transitions/react';
import '@capgo/transitions';

initTransitions({ platform: 'auto' });

export function AppShell({ children }: { children: React.ReactNode }) {
  const outletRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (!outletRef.current) return;

    return setupRouterOutlet(outletRef.current, {
      platform: 'auto',
    });
  }, []);

  return <cap-router-outlet ref={outletRef}>{children}</cap-router-outlet>;
}
HomePage.tsx
import { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { setDirection, setupPage } from '@capgo/transitions/react';

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

  useEffect(() => {
    if (!pageRef.current) return;

    return setupPage(pageRef.current, {
      onDidEnter: () => console.log('Home entered'),
    });
  }, []);

  return (
    <cap-page ref={pageRef}>
      <cap-content slot="content">
        <button
          type="button"
          onClick={() => {
            setDirection('forward');
            navigate('/details/1');
          }}
        >
          Go to Details
        </button>
      </cap-content>
    </cap-page>
  );
}

Transition Directions

DirectionUsage
forwardPush a new page. On iOS, the new page slides in from the right.
backReturn to the previous page. On iOS, the page slides back to the right.
rootReplace the navigation stack, usually with a fade.
noneChange page without an animation.

Components

ComponentRole
cap-router-outletOwns the transition stack and receives push, pop, and root changes.
cap-pageWraps one screen and emits lifecycle events.
cap-headerOptional header slot that can animate with the page.
cap-contentMain scrollable content slot.
cap-footerOptional footer slot that can animate with the page.

Lifecycle Events

cap-page emits lifecycle events so your app can coordinate data loading, focus, analytics, or cleanup.

EventWhen it runs
cap-will-enterBefore the page becomes visible.
cap-did-enterAfter the page becomes visible.
cap-will-leaveBefore the page leaves.
cap-did-leaveAfter the page leaves.

Advanced Controller

For lower-level control, create a transition controller and drive the stack manually.

transition-controller.ts
import { createTransitionController } from '@capgo/transitions';

const controller = createTransitionController({
  platform: 'auto',
  duration: 400,
  useViewTransitions: true,
});

await controller.push(detailPageElement, {
  direction: 'forward',
});

await controller.pop({
  direction: 'back',
});

await controller.setRoot(homePageElement, {
  direction: 'root',
});

Use With Native Navigation

@capgo/transitions and @capgo/capacitor-native-navigation solve different parts of the interface.

LibraryResponsibility
@capgo/transitionsAnimates web pages, headers, content, and footers inside the WebView.
@capgo/capacitor-native-navigationRenders native navbar and tabbar surfaces around the WebView.

When you use both together, keep the native bars outside the animated page content. Let Native Navigation own the bars, and let Transitions animate the route content.

Browser Support

  • Modern browsers with Web Animations API support.
  • View Transitions API support in Chrome 111+, Edge 111+, and Safari 18+.
  • Graceful fallback for browsers without View Transitions API support.

On this page

Need help with your app?

Our team can help you integrate Capstart.