23

Motion Plugin

Declarative animations powered by Motion (motion.dev)

Enter Animations with Presets

Predefined animation presets for common enter effects:

Fade

Fades in from transparent

Slide Up

Slides up while fading in

Slide Down

Slides down while fading in

Scale

Scales up from 0.9x

Bounce

Bounces in from above

Custom Enter Animations

Define your own animation parameters with full control:

From Left

x:-50, opacity:0

From Right

x:50, opacity:0

Rotate In

rotate:-15, scale:0.8

With Delay

delay:500ms

Spring Physics

Spring presets use cubic-bezier approximations. Bouncy has overshoot, slow is gradual:

Gentle

Soft and smooth

Bouncy

Playful overshoot

Tight

Snappy response

Slow

Relaxed timing

Hover Gestures

Hover over these elements to see the animation:

Scale Up

Grows on hover

Lift Up

Rises on hover

Rotate

Tilts on hover

Press Gestures

Click and hold these buttons to see press effects:

Scroll-Triggered In-View Animations

Scroll down to see these elements animate into view. Scroll away and back to see them again!

Fade In

Animates when scrolled into view

Slide Up

Slides up from below

Scale In

Scales up into view

From Left

Slides in from the left

From Right

Slides in from the right

Scroll-Linked Animations

Elements that animate based on scroll position (watch as you scroll this section):

Parallax Layer 1

Moves slower (y: 0 to -50)

Parallax Layer 2

Moves faster (y: 0 to 50)

Scale on Scroll

Scales up as you scroll (0.8 to 1.0)

Fade on Scroll

Fades in as you scroll (0.3 to 1.0)

Rotate on Scroll

Rotates as you scroll (-10 to 10 deg)

Staggered Animations

Use the delay parameter for staggered timing. The last card demonstrates data-on:motion-complete event handling.

Sequence complete:

Step 1

delay: 0ms

Step 2

delay: 200ms

Step 3

delay: 400ms

Step 4

delay: 600ms + on_complete

Visibility Helper

The visibility() helper provides a clean, single-attribute API for animated show/hide. It watches a signal and handles both enter and exit animations automatically.

Expanded:

Additional Information

This content smoothly animates in and out using the visibility() helper. The layout shift is intentional for accordion-style components.

  • Single attribute handles both enter and exit
  • Watches a signal for reactive show/hide
  • Configurable animations for each direction
# Accordion with visibility():
(show := Signal('show', False)),
Button('Toggle', data_on_click=show.toggle()),
Div(
    'Expandable content here...',
    data_motion=visibility(
        signal=show,
        enter=enter(y=-20, opacity=0, duration=400),
        exit_=exit_(y=-10, opacity=0, duration=250),
    ),
)

Repeating Animations

Use repeat() for looping animations:

Pulse (3x)

Repeats 3 times

Infinite Pulse

Repeats forever

Imperative Actions

Use motion.animate(), motion.set() for event-driven animations:

Target

Remove & Replace Actions

Use motion.remove() and motion.replace() for SSE-driven DOM changes with exit animations. The element plays its exit animation before being removed or replaced.

Remove Example

Notification 1
Notification 2
Notification 3

Replace Example (SSE)

Use motion_replace() SSE helper for animated replacements. Exit animation plays first, then new content fades in:

Version 1

Original content

# SSE endpoint with exit animation:
from starhtml.plugins import motion_replace

@rt('/update')
@sse
def update(req):
    yield motion_replace(
        "#target",
        Div('New content',
            data_motion_exit=exit_(opacity=0))
    )

Animation Sequences

Chain animations with motion.sequence() using dict() syntax for keyframes and options. Click Reset first to hide elements, then Run Sequence to see the staggered animation:

Title
Subtitle text appears after title

Resize Animations

Animations triggered by element resize. Drag the corner to resize and see the pulse effect:

Resize Me

Pulses when resized (scale bounces from 1.1x to 1x)

Playback Controls

Simple play/pause toggle with stop:

Animated Box
State: stopped

Play starts or resumes. Pause freezes at current position. Stop uses cancel() + set() to revert to original position.

Named Animations

Give animations a name to control them programmatically from anywhere:

Hero Element

Named 'hero' for remote control

# Named animations can be controlled from anywhere
motion.animate("#hero", scale=1.05, repeat="infinite", name="hero")
motion.pause("hero")  # Pause by name
motion.play("hero")   # Resume by name
motion.cancel("hero") + motion.set("#hero", scale=1)  # Stop and reset

Motion Events

Listen to animation lifecycle events. Click 'Start Slide' then quickly 'Stop' to see the cancel event:

Event log: No events yet

Event Tracked Card

Slides across over 3 seconds

data_on_motion_start=event_log.set("Started!")
data_on_motion_complete=event_log.set("Complete!")
data_on_motion_cancel=event_log.set("Cancelled!")

API Reference

Motion config is declarative - describes WHAT the animation looks like:

Animation Config Parameters

  • duration=300 - Animation duration in ms
  • delay=0 - Delay before animation starts
  • repeat=n - Repeat n times or 'infinite'
  • stagger=100 - Stagger children by delay (ms)
  • spring='bouncy' - Spring preset: gentle, bouncy, tight, slow

Event Handling

  • data_on_motion_start - Handler for animation start event
  • data_on_motion_complete - Handler for animation complete event
  • data_on_motion_cancel - Handler for animation cancel event
  • data_show=signal - Combine with Datastar for visibility

Exposed Signals

  • motion.is_animating - Boolean: animation active
  • motion.phase - Current phase: idle/enter/hover/tap
  • motion.progress - Scroll progress 0-100