- Getting Started
- The Basics
- Concepts
- SuperNative
-
EDGE Components
- Introduction
- Activity Indicator
- Badge
- Bottom Navigation
- Bottom Sheet
- Button
- Button Group
- Canvas
- Carousel
- Checkbox
- Chip
- Column
- Divider
- Gesture Area
- Icon
- Icons
- Image
- Layout & Styling
- List
- Menus
- Modal
- Pressable
- Progress Bar
- Radio Group
- Row
- Scroll View
- Select
- Shapes
- Side Navigation
- Slider
- Spacer
- Stack
- Tab Row
- Text
- Text Input
- Toggle
- Top Bar
- Virtual List
- Web View
- Plugins
- Testing
- Architecture
You're viewing pre-release documentation — version 4.x is in beta
Features, APIs and behaviour may change before the stable release. View the stable version (3.x)
Gestures & Animation
Overview#
Smooth, finger-tracking animation can't wait on a PHP round-trip — at 120fps there's no time to ask the server where a view should be. SuperNative solves this with shared values: a numeric value that lives on the native side and is mutated on the UI thread by gestures and animations. PHP holds only an opaque handle; the per-frame numbers never cross the boundary.
If you've used Reanimated in React Native, this is the same idea.
Shared values#
Create one in PHP with SharedValue::make($initial), bind it to a gesture, and read it from any animatable prop:
@php $drag = \Native\Mobile\Edge\SharedValue::make(); @endphp <native:gesture-area :pan-y="$drag" @drag-end="onRelease"> <native:column :translate-y="$drag" :opacity="$drag->interpolate([0, 200], [1, 0])" :scale="$drag->interpolate([0, 200], [1, 0.7])" class="p-6 bg-theme-surface rounded-2xl"> <native:text>Pull me down</native:text> </native:column></native:gesture-area>
As the user drags, $drag updates on the UI thread and the bound props follow instantly — the card moves, fades,
and shrinks together, with no PHP involved during the gesture.
Formulas#
Rather than bind the raw value everywhere, derive from it with a chainable formula. Each method returns a new derived value, so one gesture can drive many props differently:
->interpolate([$inMin, $inMax], [$outMin, $outMax])— linearly remap a range (clamps at the ends).->clamp($min, $max)— constrain to a range.->multiply($factor)— scale.->add($offset)— shift.
$drag->interpolate([0, 200], [1, 0]); // 0→1, 200→0, fully faded past 200
Animatable props that accept a shared value: translate-x, translate-y, scale, rotate, and opacity.
Reacting when the gesture ends#
Per-frame values stay on the native side, but you often need PHP to make a decision when the user lets go — commit
or snap back. The <native:gesture-area> fires @drag-end with the final
value:
public function onRelease(float $value): void{ if ($value > 150) { $this->dismiss(); // dragged far enough — commit } // otherwise the view springs back to its resting position}
Call ->value() on a shared value inside such a handler to read its PHP-side snapshot (with any formula applied)
if you need the derived number rather than the raw translation.
Property animations#
Any element animates when a value you bind to it changes between renders — no shared value, no gesture. Wrap the
change in animate-duration (milliseconds) and the element eases from its old value to the new one on the next
render. The animatable props are translate-x, translate-y, scale, rotate, and opacity:
{{-- A panel slides up from below when $shown flips to true --}}<native:column :translate-y="$shown ? 0 : 120" :animate-duration="450" animate-easing="ease-out" class="bg-theme-surface rounded-2xl p-4"> <native:text>Surprise!</native:text></native:column>
Toggle $shown in a method and the panel eases into place — there's no animation code to write beyond the props.
Duration & easing#
animate-duration— length in milliseconds (e.g.250). Without it, a change snaps instantly.animate-easing— the curve:linear,ease-in,ease-out, orease-in-out.
Combine transforms freely under one duration — a card can slide, fade, and scale at once by animating
translate-y, opacity, and scale together.
Looping#
Set animate-loop to repeat an animation continuously — a pulsing dot, a breathing highlight:
<native:column :scale="$pulsing ? 1.15 : 1.0" :animate-duration="600" :animate-loop="true"> <native:icon name="heart.fill" /></native:column>
Press feedback#
Press feedback is a special case: it reacts the instant a finger touches down — before any PHP round-trip — so a tap feels immediate. Set any of these on a pressable element and the effect holds while pressed, then springs back on release:
press-scale— scale while pressed (e.g.0.9to shrink slightly)press-opacity— dim while pressed (e.g.0.55)press-translate-y— nudge down while pressed (e.g.3)
<native:pressable :press-scale="0.92" :press-opacity="0.85" :press-translate-y="3" @press="open"> <native:text>Press me</native:text></native:pressable>
Unlike animate-* (which runs when a re-render changes a value), press feedback needs no state and no handler —
the native side plays it locally on touch.
in no time