The biggest update yet: seven new features, zero breaking changes, and a much better experience on mobile and for accessibility.
Introduction
@gfazioli/mantine-flip is a Mantine component that turns any two views into a smooth 3D flip card — perfect for settings panels, sign-in/sign-up toggles, credit card UIs, and widget grids. This release brings compound components for a clearer API, touch swipe support for mobile, a spring easing curve for natural-feeling animations, lazy rendering for performance, and proper accessibility — all while staying fully backward-compatible with existing code.
What's New
Compound Components: Flip.Front and Flip.Back
Until now, Flip relied on child order to distinguish the front from the back face. That worked, but it wasn't immediately obvious which child was which. You can now use named compound components for a more explicit, self-documenting API:
<Flip h={200} w={400}>
<Flip.Front>
<Paper p="lg" withBorder>
<Text>Front face</Text>
<Flip.Target>
<Button>Show back</Button>
</Flip.Target>
</Paper>
</Flip.Front>
<Flip.Back>
<Paper p="lg" withBorder>
<Text>Back face</Text>
<Flip.Target>
<Button>Show front</Button>
</Flip.Target>
</Paper>
</Flip.Back>
</Flip>
The classic two-children approach still works exactly as before — no migration required.
Touch Swipe Support
Flip cards are a natural fit for mobile, and now they behave like it. Enable swipeable to let users flip the card with a swipe gesture. The swipe direction automatically matches the direction prop, and you can fine-tune sensitivity with swipeThreshold:
<Flip swipeable swipeThreshold={60} direction="horizontal">
{/* ... */}
</Flip>
The implementation uses passive touch event listeners for zero scroll-blocking overhead.
Spring Easing
CSS transitions don't have to feel mechanical. Set easing="spring" and the flip gains a physics-based bounce powered by a CSS linear() curve — no JavaScript animation library needed:
<Flip easing="spring">
{/* ... */}
</Flip>
The spring curve is carefully tuned: a quick overshoot followed by a gentle settle, giving the flip a tactile, almost physical quality. Compare it side by side with the default ease-in-out in the live docs.
Lazy Back Rendering
If you're rendering a grid of flip cards, the back faces are invisible but still in the DOM — potentially holding heavy content like forms, images, or data tables. The new lazyBack prop defers back-face rendering until the user actually flips the card for the first time:
<Flip lazyBack>
{/* Front: always rendered */}
{/* Back: rendered only after the first flip */}
</Flip>
This can significantly reduce initial DOM size and improve time-to-interactive in card-heavy layouts.
Disabled State
Need to temporarily prevent flipping? The disabled prop blocks all interactions — Flip.Target clicks and programmatic toggleFlip calls are both ignored:
<Flip disabled>
{/* ... */}
</Flip>
Flip.Target automatically receives data-disabled and aria-disabled attributes, so you can style the disabled state with plain CSS:
[data-disabled] {
opacity: 0.5;
cursor: not-allowed;
}
onTransitionEnd Callback
Know exactly when the flip animation finishes. The callback fires once the flip container's own CSS transform transition completes (bubbled transitions from children are ignored) — useful for focusing an input on the back face, fetching data, or chaining animations:
<Flip onTransitionEnd={() => backInputRef.current?.focus()}>
{/* ... */}
</Flip>
Expanded Type Exports
FlipProps, FlipTargetProps, FlipFrontProps, and FlipBackProps are now exported directly from the package, making it easier to type wrapper components and custom abstractions.
Bug Fixes
CSS Variable Fallbacks Fixed
CSS fallback values in var() expressions were incorrectly quoted (e.g., var(--flip-perspective, '1000px')). Quoted fallbacks are invalid CSS and were silently ignored in some browsers, causing the component to render with no perspective or transition. All fallbacks are now unquoted and valid.
Direction Change No Longer Desyncs State
Changing direction, directionFlipIn, or directionFlipOut at runtime previously caused several edge cases: the visual rotation and logical flipped state could go out of sync, and changing direction while not flipped could block subsequent flips. All direction-change edge cases are now handled correctly, including proper behavior in controlled mode (where the parent owns the flipped prop).
Controlled Mode + lazyBack Fixed
Using <Flip flipped={true} lazyBack> on initial render left the back face blank. The component now correctly initializes the lazy-back ref from the effective flipped value.
Safari Backface Bleed-Through
Added -webkit-backface-visibility: hidden to fix the back face showing through on Safari and older WebKit browsers. Also added transform-style: preserve-3d on the root element to prevent 3D flattening in certain layout contexts.
Improvements
Accessibility
The component is now screen-reader friendly out of the box:
-
aria-live="polite"on the root announces flip state changes - Front/back faces use the
inertattribute to control focusability — the non-visible face becomes completely non-interactive, avoiding the commonaria-hiddenwarning when a focused element is inside a hidden container -
Flip.Targetrendersaria-disabledwhen the flip is disabled
Performance
- Swipe touch listeners use a stable ref and are only re-attached when
swipeable,direction, orswipeThresholdchange — not on every flip -
will-change: transformon the flip container hints the browser to promote the element to its own compositing layer -
lazyBack(see above) reduces initial DOM weight for card grids — and disabling it at runtime immediately mounts the back face
Interactive Configurator
The docs configurator now uses a numeric slider for the perspective control (range 0–5000, step 100) instead of a plain text input, and includes the new "Spring" option in the easing dropdown. Try it live to feel the difference each parameter makes.
New Props at a Glance
| Prop | Type | Default | Description |
|---|---|---|---|
disabled |
boolean |
false |
Blocks all flip interactions |
lazyBack |
boolean |
false |
Defers back-face rendering until first flip |
swipeable |
boolean |
false |
Enables touch swipe gestures |
swipeThreshold |
number |
50 |
Minimum swipe distance (px) to trigger flip |
easing |
`string \ | 'spring'` | 'ease-in-out' |
onTransitionEnd |
() => void |
— | Called when flip animation completes |
Installation & Update
# Install
npm install @gfazioli/mantine-flip
# or
yarn add @gfazioli/mantine-flip
Import styles at your app root:
import '@gfazioli/mantine-flip/styles.css';
This release has no breaking changes — update and all existing code continues to work as-is.
Compatibility
-
Mantine
>=7.0.0 -
React
18.xor19.x
Top comments (0)