App Store-style shared element transitions for React.
Tap a card and it morphs into a detail view — then morphs back. Aperto wraps the browser's native View Transitions API in a small set of headless, composable React parts: no animation library, no FLIP math, zero dependencies, ~5 kB gzipped.
import * as Aperto from "aperto"
import "aperto/styles.css"
<Aperto.Root>
<Aperto.Card id="album-1">
<Aperto.Shared name="cover" kind="media">
<img src="/cover.jpg" alt="" />
</Aperto.Shared>
</Aperto.Card>
<Aperto.Detail id="album-1">
<Aperto.Overlay />
<Aperto.Shared name="cover" kind="media">
<img src="/cover.jpg" alt="" />
</Aperto.Shared>
<Aperto.Title>Album title</Aperto.Title>
<Aperto.Close>Close</Aperto.Close>
</Aperto.Detail>
</Aperto.Root>Status: early preview. The API is small and settling, but expect changes before 1.0.
Live demos and full API reference: aperto.alexpate.com
- Native first —
document.startViewTransition()does the animation. The browser owns every frame. - Headless — plain markup and your CSS. State arrives as
data-stateattributes; the morph is styled with::view-transition-*selectors and custom properties. - Interruption-safe — mash open and close mid-flight and it settles on your last intent.
- Accessible — dialog semantics, background
inert, focus management, Esc to close, automatic labelling. - Honest fallback — no View Transitions support, or reduced motion? Same components, instant swap. Feature detection, never UA sniffing.
- Tiny — ~5 kB gzipped with zero dependencies; the standalone
useViewTransition()engine is under 1 kB.
| Package | Description |
|---|---|
aperto |
The library, published to npm. |
www |
Docs and demo site — aperto.alexpate.com. |
packages/
aperto/ # the library: components, engine, preset stylesheets
www/ # Next.js docs site
Prerequisites: Node 24+ and pnpm 10.
pnpm install
pnpm dev # docs site + library in watch mode
pnpm test # unit tests (vitest)
pnpm build # build all packages
pnpm lint # biome
pnpm size # bundle size budgets- Bump
versioninpackages/aperto/package.json. cd packages/aperto && pnpm publish(runs the build viaprepublishOnly).- Tag:
git tag vX.Y.Z && git push origin vX.Y.Z.
MIT © Alex Pate
