CircleReveal
Iris/circle-wipe transition — animates clip-path: circle(…) from a point outward (open) or from full coverage back to a point (close). Use it as a one-shot reveal on any element, or wire it into route changes with the companion PageIris wrapper for full page transitions.
mode=open · origin=50% 50%
iris open
Usage
import { CircleReveal } from '@bwo-ui/react';
// One-shot iris-open on a hero image
<CircleReveal mode="open" duration={0.9}>
<img src="/hero.jpg" alt="" />
</CircleReveal>
// Off-center origin (15% from the left, 15% from the top)
<CircleReveal mode="open" origin={{ x: '15%', y: '15%' }}>
<Card />
</CircleReveal>
// Close-iris dismissal — fires onComplete when finished
<CircleReveal mode="close" duration={0.5} onComplete={() => setShown(false)}>
<Modal />
</CircleReveal>Page transitions with PageIris
PageIris wraps your route content with a CircleReveal that replays whenever its pathname prop changes — so every navigation gets a fresh iris-open. It's framework-agnostic: pass usePathname() in Next.js, useLocation().pathname in React Router, or any string that changes per route.
// app/layout.tsx (Next.js)
'use client';
import { usePathname } from 'next/navigation';
import { PageIris } from '@bwo-ui/react';
export default function RootLayout({ children }) {
const pathname = usePathname();
return (
<html lang="en">
<body>
<PageIris pathname={pathname ?? '/'} duration={0.8}>
{children}
</PageIris>
</body>
</html>
);
}CircleReveal props
| Prop | Type | Default | Description |
|---|---|---|---|
mode | 'open' | 'close' | 'open' | open animates the visible circle from origin outward. close shrinks the visible circle back into the origin. |
origin | { x?: number | string; y?: number | string } | { x: '50%', y: '50%' } | Centre of the circle. Numbers convert to percent, strings pass through (e.g. "120px", "center"). Defaults to the geometric centre of the element. |
duration | number | 0.7 | Animation duration in seconds. |
ease | string | 'expo.inOut' | GSAP ease. |
delay | number | 0 | Initial delay before the tween starts. |
onComplete | () => void | — | Fires when the animation finishes. Use it to unmount the element after a close iris. |
prime | boolean | true | Synchronously set the start clip-path on mount so the first frame matches. Set to false if you need GSAP to manage the initial state itself. |
as | ElementType | 'div' | HTML tag or component to render the wrapping element as. |
PageIris props
| Prop | Type | Default | Description |
|---|---|---|---|
pathname | string | — | Anything that changes on route change. Pass usePathname() / useLocation().pathname / your own key. The iris replays whenever this value changes. |
duration | number | 0.8 | Animation duration in seconds. |
ease | string | 'expo.out' | GSAP ease. |
origin | { x?: number | string; y?: number | string } | { x: '50%', y: '50%' } | Centre of the iris. Same shape as CircleReveal#origin. |
className | string | — | Wrapper className — useful for sizing the iris container. |
style | React.CSSProperties | — | Wrapper inline styles. |