Skip to content

GSAP Motion

GSAP Motion is an optional integration for richer, opinionated animation. Core Faststrap still uses Fx for zero-JS effects; use this integration only when a project explicitly wants GSAP.

Install

pip install faststrap

The gsap extra is intentionally dependency-free in the Python package. GSAP itself is loaded from CDN by add_gsap(app) unless you pass a custom URL.

Faststrap exposes GSAP_VERSION and GSAP_CDN_URL when you need to inspect or reuse the default pinned asset. GsapPreset and MotionPreset are type aliases for the supported preset names.

App Setup

from fasthtml.common import FastHTML
from faststrap import add_bootstrap, add_gsap

app = FastHTML()
add_bootstrap(app)
add_gsap(app)

add_gsap(app) is idempotent, so repeated startup wiring will not add duplicate script tags.

Component Motion

from faststrap import Card, Gsap

Card(
    "Revenue is up 12%",
    header="Today",
    **Gsap.fade_up_attrs(duration=0.5, delay=0.1),
)

You can also use the generic helper when the preset is dynamic:

Card("Pipeline refreshed", **Gsap.attrs(Gsap.pop, duration=0.35))

Reveal Wrapper

from faststrap import Button, Motion

Motion(
    Button("Save", variant="primary"),
    preset="pop",
)

Motion is an alias for GsapReveal. Use whichever name reads better in your app.

Staggered Children

from faststrap import Card, Row, Gsap

Row(
    Card("One"),
    Card("Two"),
    Card("Three"),
    **Gsap.stagger_attrs("fade-up", stagger=0.08),
)

Presets

  • fade
  • fade-up
  • fade-down
  • slide-left
  • slide-right
  • scale
  • pop

Python Helpers

  • Gsap.attrs(...)
  • Gsap.fade_attrs(...)
  • Gsap.fade_up_attrs(...)
  • Gsap.fade_down_attrs(...)
  • Gsap.slide_left_attrs(...)
  • Gsap.slide_right_attrs(...)
  • Gsap.scale_attrs(...)
  • Gsap.pop_attrs(...)
  • Gsap.stagger_attrs(...)

Philosophy

  • GSAP is never required for core Faststrap components.
  • Server-rendered markup remains usable without GSAP.
  • The runtime respects prefers-reduced-motion.
  • Use GSAP for premium motion, guided flows, and showcase-level polish, not basic layout behavior.

API Reference

faststrap.integrations.gsap.gsap_assets(*, version=GSAP_VERSION, cdn_url=None, include_init=True, defer=True)

Return script tags required by the Faststrap GSAP integration.

Source code in src/faststrap/integrations/gsap.py
def gsap_assets(
    *,
    version: str = GSAP_VERSION,
    cdn_url: str | None = None,
    include_init: bool = True,
    defer: bool = True,
) -> tuple[Any, ...]:
    """Return script tags required by the Faststrap GSAP integration."""
    source = cdn_url or f"https://cdn.jsdelivr.net/npm/gsap@{version}/dist/gsap.min.js"
    assets: list[Any] = [Script(src=source, defer=defer)]
    if include_init:
        assets.append(Script(NotStr(GSAP_INIT_SCRIPT)))
    return tuple(assets)

faststrap.integrations.gsap.add_gsap(app, *, version=GSAP_VERSION, cdn_url=None, include_init=True, defer=True)

Attach GSAP assets to a FastHTML app once.

Use this only in projects that intentionally opt into richer client-side motion. Core Faststrap components do not depend on GSAP.

Source code in src/faststrap/integrations/gsap.py
def add_gsap(
    app: Any,
    *,
    version: str = GSAP_VERSION,
    cdn_url: str | None = None,
    include_init: bool = True,
    defer: bool = True,
) -> None:
    """Attach GSAP assets to a FastHTML app once.

    Use this only in projects that intentionally opt into richer client-side
    motion. Core Faststrap components do not depend on GSAP.
    """
    if getattr(app, "_faststrap_gsap_loaded", False):
        return

    app.hdrs.extend(
        gsap_assets(version=version, cdn_url=cdn_url, include_init=include_init, defer=defer)
    )
    app._faststrap_gsap_loaded = True

faststrap.integrations.gsap.Gsap

Python-friendly GSAP motion presets for Faststrap components.

Source code in src/faststrap/integrations/gsap.py
class Gsap:
    """Python-friendly GSAP motion presets for Faststrap components."""

    fade = "fade"
    fade_up = "fade-up"
    fade_down = "fade-down"
    slide_left = "slide-left"
    slide_right = "slide-right"
    scale = "scale"
    pop = "pop"

    @staticmethod
    def attrs(
        preset: GsapPreset = "fade-up",
        *,
        duration: float | None = None,
        delay: float | None = None,
        ease: str | None = None,
        stagger: float | None = None,
        **kwargs: Any,
    ) -> dict[str, Any]:
        """Return data attributes consumed by the Faststrap GSAP runtime."""
        _validate_preset(preset)
        attrs: dict[str, Any] = {"data_fs_gsap": preset}

        if duration is not None:
            attrs["data_fs_gsap_duration"] = str(duration)
        if delay is not None:
            attrs["data_fs_gsap_delay"] = str(delay)
        if ease is not None:
            attrs["data_fs_gsap_ease"] = ease
        if stagger is not None:
            attrs["data_fs_gsap_stagger"] = str(stagger)

        attrs.update(kwargs)
        return convert_attrs(attrs)

    reveal = attrs
    reveal_attrs = attrs

    @staticmethod
    def fade_attrs(**kwargs: Any) -> dict[str, Any]:
        """Return attributes for a fade reveal."""
        return Gsap.attrs("fade", **kwargs)

    @staticmethod
    def fade_up_attrs(**kwargs: Any) -> dict[str, Any]:
        """Return attributes for a fade-up reveal."""
        return Gsap.attrs("fade-up", **kwargs)

    @staticmethod
    def fade_down_attrs(**kwargs: Any) -> dict[str, Any]:
        """Return attributes for a fade-down reveal."""
        return Gsap.attrs("fade-down", **kwargs)

    @staticmethod
    def slide_left_attrs(**kwargs: Any) -> dict[str, Any]:
        """Return attributes for a slide-left reveal."""
        return Gsap.attrs("slide-left", **kwargs)

    @staticmethod
    def slide_right_attrs(**kwargs: Any) -> dict[str, Any]:
        """Return attributes for a slide-right reveal."""
        return Gsap.attrs("slide-right", **kwargs)

    @staticmethod
    def scale_attrs(**kwargs: Any) -> dict[str, Any]:
        """Return attributes for a scale reveal."""
        return Gsap.attrs("scale", **kwargs)

    @staticmethod
    def pop_attrs(**kwargs: Any) -> dict[str, Any]:
        """Return attributes for a pop reveal."""
        return Gsap.attrs("pop", **kwargs)

    @staticmethod
    def stagger_attrs(
        preset: GsapPreset = "fade-up",
        *,
        stagger: float = 0.08,
        **kwargs: Any,
    ) -> dict[str, Any]:
        """Return attributes for revealing a container's children in sequence."""
        return Gsap.attrs(preset, stagger=stagger, **kwargs)

attrs(preset='fade-up', *, duration=None, delay=None, ease=None, stagger=None, **kwargs) staticmethod

Return data attributes consumed by the Faststrap GSAP runtime.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def attrs(
    preset: GsapPreset = "fade-up",
    *,
    duration: float | None = None,
    delay: float | None = None,
    ease: str | None = None,
    stagger: float | None = None,
    **kwargs: Any,
) -> dict[str, Any]:
    """Return data attributes consumed by the Faststrap GSAP runtime."""
    _validate_preset(preset)
    attrs: dict[str, Any] = {"data_fs_gsap": preset}

    if duration is not None:
        attrs["data_fs_gsap_duration"] = str(duration)
    if delay is not None:
        attrs["data_fs_gsap_delay"] = str(delay)
    if ease is not None:
        attrs["data_fs_gsap_ease"] = ease
    if stagger is not None:
        attrs["data_fs_gsap_stagger"] = str(stagger)

    attrs.update(kwargs)
    return convert_attrs(attrs)

fade_attrs(**kwargs) staticmethod

Return attributes for a fade reveal.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def fade_attrs(**kwargs: Any) -> dict[str, Any]:
    """Return attributes for a fade reveal."""
    return Gsap.attrs("fade", **kwargs)

fade_down_attrs(**kwargs) staticmethod

Return attributes for a fade-down reveal.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def fade_down_attrs(**kwargs: Any) -> dict[str, Any]:
    """Return attributes for a fade-down reveal."""
    return Gsap.attrs("fade-down", **kwargs)

fade_up_attrs(**kwargs) staticmethod

Return attributes for a fade-up reveal.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def fade_up_attrs(**kwargs: Any) -> dict[str, Any]:
    """Return attributes for a fade-up reveal."""
    return Gsap.attrs("fade-up", **kwargs)

pop_attrs(**kwargs) staticmethod

Return attributes for a pop reveal.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def pop_attrs(**kwargs: Any) -> dict[str, Any]:
    """Return attributes for a pop reveal."""
    return Gsap.attrs("pop", **kwargs)

scale_attrs(**kwargs) staticmethod

Return attributes for a scale reveal.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def scale_attrs(**kwargs: Any) -> dict[str, Any]:
    """Return attributes for a scale reveal."""
    return Gsap.attrs("scale", **kwargs)

slide_left_attrs(**kwargs) staticmethod

Return attributes for a slide-left reveal.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def slide_left_attrs(**kwargs: Any) -> dict[str, Any]:
    """Return attributes for a slide-left reveal."""
    return Gsap.attrs("slide-left", **kwargs)

slide_right_attrs(**kwargs) staticmethod

Return attributes for a slide-right reveal.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def slide_right_attrs(**kwargs: Any) -> dict[str, Any]:
    """Return attributes for a slide-right reveal."""
    return Gsap.attrs("slide-right", **kwargs)

stagger_attrs(preset='fade-up', *, stagger=0.08, **kwargs) staticmethod

Return attributes for revealing a container's children in sequence.

Source code in src/faststrap/integrations/gsap.py
@staticmethod
def stagger_attrs(
    preset: GsapPreset = "fade-up",
    *,
    stagger: float = 0.08,
    **kwargs: Any,
) -> dict[str, Any]:
    """Return attributes for revealing a container's children in sequence."""
    return Gsap.attrs(preset, stagger=stagger, **kwargs)

faststrap.integrations.gsap.GsapReveal(*children, preset='fade-up', duration=None, delay=None, ease=None, stagger=None, **kwargs)

Wrap children in a motion-enabled container.

Source code in src/faststrap/integrations/gsap.py
def GsapReveal(
    *children: Any,
    preset: GsapPreset = "fade-up",
    duration: float | None = None,
    delay: float | None = None,
    ease: str | None = None,
    stagger: float | None = None,
    **kwargs: Any,
) -> Div:
    """Wrap children in a motion-enabled container."""
    user_cls = kwargs.pop("cls", "")
    attrs = Gsap.attrs(
        preset,
        duration=duration,
        delay=delay,
        ease=ease,
        stagger=stagger,
        **kwargs,
    )
    attrs["cls"] = merge_classes("faststrap-gsap-reveal", user_cls)
    return Div(*children, **attrs)