Skip to main content

Transition

Transition is a lightweight animation helper for one common visual property on one child.

Use it when a state change should ease visually instead of snapping immediately. Typical cases are fading content in, sliding a panel slightly, scaling a pressed card, or rotating a small affordance. It is deliberately smaller than a full animation system. You give it a stable id, a target value, a property, and timing information. The runtime then animates from the current visible value to the new one.

This fits Fission's architecture well because the animation target still comes from explicit state. Your reducer decides that show_banner is now true. build() then describes the banner with a new opacity or translation value. Transition requests the runtime animation, but it does not invent hidden product state of its own.

Example

use fission::core::{AnimationPropertyId, WidgetNodeId};
use fission::prelude::*;

let banner = Transition {
id: WidgetNodeId::explicit("save_banner"),
property: AnimationPropertyId::Opacity,
value: if view.state.show_saved_banner { 1.0 } else { 0.0 },
duration: 250,
delay: 0,
child: Box::new(saved_banner.build(ctx, view)),
}
.build(ctx, view);

Field table

FieldTypeMeaningNotes / default behavior
idWidgetNodeIdStable animation target identity.Required. Reuse the same id across rebuilds so the runtime can animate from the current visual state.
valuef32Target value for the chosen property.Defaults to 0.0. Interpret it according to property.
propertyAnimationPropertyIdWhich visual property to animate.Defaults to Opacity.
durationu64Animation duration in milliseconds.Defaults to 300.
delayu64Delay before the animation starts, in milliseconds.Defaults to 0.
childBox<Node>Content that should visually transition.Required. The widget wraps it in a repaint boundary for the built-in properties.

When to use it and when not to

Transition is the right tool when you want one straightforward, state-driven animation on a subtree. It is not the right tool for choreographed multi-element sequences, physics-driven motion, or route-to-route shared element behavior. Those cases usually want a more intentional animation structure such as Hero, nested transitions, or a custom runtime animation strategy.

Specific advice

Keep the id stable and meaningful. If you generate a new id every rebuild, the runtime has no previous visual state to animate from.

Also know the current limits of this helper. The built-in widget applies compositor-friendly wrappers for Opacity, TranslateX, TranslateY, Scale, and Rotation. If you pass AnimationPropertyId::Custom(_), the current implementation leaves the child visually unchanged, so use a lower-level path for truly custom animated properties.

Hero, Composite, and Rendering pipeline.