An open API service indexing awesome lists of open source software.

https://github.com/lemoncloud-io/page-transition

iOS/Android style page transitions for React, Vue, and Angular using View Transitions API
https://github.com/lemoncloud-io/page-transition

android angular animations capacitor cordova hybrid-apps ionic ios mobile page-transitions react react-native react-router typescript view-transitions-api vue vue-router webview

Last synced: 3 months ago
JSON representation

iOS/Android style page transitions for React, Vue, and Angular using View Transitions API

Awesome Lists containing this project

README

          

# Page Transition

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)

**iOS/Android-style page transitions using the [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API).**
Built for hybrid mobile apps that need native-feeling navigation in WebView.

| iOS Style | Android Style |
|:---------:|:-------------:|
| ![iOS](https://raw.githubusercontent.com/lemoncloud-io/page-transition/main/.github/ios.gif) | ![Android](https://raw.githubusercontent.com/lemoncloud-io/page-transition/main/.github/android.gif) |
| Horizontal slide (350ms) | Vertical lift (450ms) |

## Features

- iOS/Android platform auto-detection
- Multiple animation types (slide, lift, fade, zoom)
- Customizable via CSS custom properties (`--pt-*`)
- Per-navigation timing override (duration, easing)
- Promise-based navigation
- SSR safe
- Zero dependencies (except framework peer deps)

## Packages

| Package | Version | Size | Description |
|---------|---------|------|-------------|
| [@lemoncloud/react-page-transition](./packages/react) | [![npm](https://img.shields.io/npm/v/@lemoncloud/react-page-transition.svg)](https://www.npmjs.com/package/@lemoncloud/react-page-transition) | [![size](https://img.shields.io/bundlephobia/minzip/@lemoncloud/react-page-transition)](https://bundlephobia.com/package/@lemoncloud/react-page-transition) | React hooks |
| [@lemoncloud/vue-page-transition](./packages/vue) | [![npm](https://img.shields.io/npm/v/@lemoncloud/vue-page-transition.svg)](https://www.npmjs.com/package/@lemoncloud/vue-page-transition) | [![size](https://img.shields.io/bundlephobia/minzip/@lemoncloud/vue-page-transition)](https://bundlephobia.com/package/@lemoncloud/vue-page-transition) | Vue composables |
| [@lemoncloud/page-transition-core](./packages/core) | [![npm](https://img.shields.io/npm/v/@lemoncloud/page-transition-core.svg)](https://www.npmjs.com/package/@lemoncloud/page-transition-core) | [![size](https://img.shields.io/bundlephobia/minzip/@lemoncloud/page-transition-core)](https://bundlephobia.com/package/@lemoncloud/page-transition-core) | Core + CSS |

> **Angular 17+:** Uses built-in `withViewTransitions()`. Only needs CSS from core package.

## Quick Start

### React

```bash
npm install @lemoncloud/react-page-transition
```

```tsx
// main.tsx
import '@lemoncloud/page-transition-core/styles.css';
import { useNavigateWithTransition } from '@lemoncloud/react-page-transition';

function MyComponent() {
const navigate = useNavigateWithTransition();

return (
<>
navigate('/settings')}>Settings
navigate(-1)}>Back
>
);
}
```

### Vue

```bash
npm install @lemoncloud/vue-page-transition
```

```vue

import '@lemoncloud/page-transition-core/styles.css';
import { useNavigateWithTransition } from '@lemoncloud/vue-page-transition';

const { navigate, goBack } = useNavigateWithTransition();

Settings
Back

```

### Angular

```bash
npm install @lemoncloud/page-transition-core
```

```typescript
// main.ts
import { provideRouter, withViewTransitions } from '@angular/router';

bootstrapApplication(AppComponent, {
providers: [provideRouter(routes, withViewTransitions())]
});
```

```json
// angular.json - add to styles array
"styles": [
"node_modules/@lemoncloud/page-transition-core/dist/styles.css",
"src/styles.css"
]
```

## API

```ts
const navigate = useNavigateWithTransition({
platform?: 'ios' | 'android' | 'auto', // default: 'auto'
detectPlatform?: () => 'ios' | 'android' | undefined
});

// Navigation
navigate('/path'); // Forward
navigate(-1); // Back
navigate('/home', { direction: 'back' }); // Path with back animation
navigate('/modal', { animation: 'fade' }); // Custom animation
navigate('/tab', { replace: true }); // No transition (tab switch)

// Per-navigation customization
navigate('/modal', {
animation: 'fade',
customization: { duration: 500, easing: 'ease-in-out' }
});
```

### Animation Types

| Type | Duration | Use Case |
|------|----------|----------|
| `slide` | 350ms | iOS default - horizontal |
| `lift` | 450ms | Android default - vertical |
| `fade` | 350ms | Modals, overlays |
| `zoom` | 350ms | Galleries, images |
| `none` | 0ms | Instant switch |

## Customization

### CSS Custom Properties

Override default animation timings globally via CSS variables:

```css
:root {
/* iOS Slide */
--pt-slide-duration: 500ms;
--pt-slide-easing: ease-in-out;

/* Android Lift */
--pt-lift-duration: 500ms;
--pt-lift-easing: ease-out;

/* Fade */
--pt-fade-duration: 500ms;
--pt-fade-easing: ease-in-out;

/* Zoom */
--pt-zoom-duration: 500ms;
--pt-zoom-easing: ease-in-out;
}
```

### Per-Navigation Override

Override timing for a single navigation via the `customization` option:

```tsx
// React
navigate('/modal', {
animation: 'fade',
customization: { duration: 500, easing: 'ease-in-out' }
});
```

```vue

navigate('/modal', {
animation: 'fade',
customization: { duration: 500, easing: 'ease-in-out' }
});

```

### CSS Variable Reference

| Variable | Default | Description |
|----------|---------|-------------|
| `--pt-slide-duration` | `350ms` | iOS slide animation duration |
| `--pt-slide-easing` | `cubic-bezier(0.32, 0.72, 0, 1)` | iOS slide easing |
| `--pt-lift-duration` | `450ms` | Android lift animation duration |
| `--pt-lift-easing` | `cubic-bezier(0.2, 0, 0, 1)` | Android lift easing (MD3 Emphasized) |
| `--pt-fade-duration` | `350ms` | Fade animation duration |
| `--pt-fade-easing` | `cubic-bezier(0.42, 0, 0.58, 1)` | Fade easing (ease-in-out) |
| `--pt-zoom-duration` | `350ms` | Zoom animation duration |
| `--pt-zoom-easing` | `cubic-bezier(0.32, 0.72, 0, 1)` | Zoom easing (iOS spring) |

## Browser Support

| Browser | Version |
|---------|---------|
| Chrome | 111+ |
| Edge | 111+ |
| Safari | 18+ |
| Firefox | 133+ |

Unsupported browsers fall back to instant navigation (no animation).

## Development

```bash
pnpm install
pnpm build # Build all packages
pnpm dev # Watch mode
pnpm test # Run tests (42 tests)
```

### Examples

```bash
pnpm --filter @example/basic dev # React - localhost:3000
pnpm --filter @example/vue dev # Vue - localhost:3001
pnpm --filter @example/angular dev # Angular - localhost:4200
```

## Contributing

1. Fork the repository
2. Create feature branch (`git checkout -b feature/amazing`)
3. Commit changes (`git commit -m 'feat: add amazing feature'`)
4. Push (`git push origin feature/amazing`)
5. Open Pull Request

## License

MIT © [LemonCloud](https://lemoncloud.io)