zedkit
@zedtech/zedkit-ui

Animate

alpha

One typed attribute and wrapper API for identity-token motion, with a tiny SSR-safe runtime.

Invoice
Appears on scroll, presses down.
View props table
Who is it for?
Developers adding appear, scroll, press, longpress, hover or focus motion to any kit element.
When should I use it?
When a card, section or control should move on appear, scroll progress, press, longpress, hover or focus.
When should I pick something else?
For pinned scene crossfades use `ScrollScenes`. For section snap/smooth-scroll use `SectionScroll`. For first-paint class utilities see `Animate entrances and hover feedback with CSS utilities`.

Install or copy

This ships on npm only; there is no copy-source brick for it.

You get
Every component from one import, with the theme tokens included. Updates arrive with your package manager.
You need
  • React 19 and Tailwind CSS 4, for example a Next.js app created with the Tailwind option.
  1. Install

    Terminal
    pnpm add @zedtech/zedkit-ui
  2. Load the styles

    Tailwind does not scan node_modules, so the @source line points it at the kit's class names. The path is relative to this file.

    src/app/globals.cssReplace the contents
    @import "tailwindcss";
    @import "@zedtech/zedkit-ui/styles.css";
    @source "../../node_modules/@zedtech/zedkit-ui/src/**/*.{ts,tsx}";
    
  3. Import and render

    src/app/page.tsxReplace the contents
    import { AnimateObserver, Card } from "@zedtech/zedkit-ui";
    
    export default function Page() {
      return (
        <main className="p-8">
          <AnimateObserver />
          <Card data-animate="fade-up" data-animate-delay="100" data-animate-press="scale-down">
            Invoice
          </Card>
        </main>
      );
    }
    

Package version 1.6.2.

Usage and states

Attribute on a card
import { AnimateObserver, Card } from "@zedtech/zedkit-ui";

<AnimateObserver />
<Card data-animate="fade-up" data-animate-delay="100" data-animate-press="scale-down">
  Invoice
</Card>

Wrapper with several triggers

Hold to pulse. Scroll to shift.

import { Animate } from "@zedtech/zedkit-ui";

<Animate on={{ appear: "fade-up", press: "scale-down", longpress: "pulse", scroll: "parallax" }}>
  Band
</Animate>

Stagger children

Write the launch email

Review the product photos

Publish the sale banner

import { Animate, Stack, Text } from "@zedtech/zedkit-ui";

<Animate on={{ appear: "fade-up" }} stagger>
  <Stack>
    <Text>One</Text>
    <Text>Two</Text>
  </Stack>
</Animate>

Wraps: (none)

Props

Prop

Type

Show inherited HTML attributes

Standard attributes from the underlying element. See MDN.

Prop

Type

Accessibility

prefers-reduced-motion: reduce leaves content visible and in place. Hover is gated to hover-capable pointers. Focus uses :focus-visible. Press ignores disabled. Longpress is decorative, never the only action. Appear does not set aria-hidden.

Troubleshooting

Nothing appears to move — mount `<AnimateObserver />` once near the app root (or call `observeAnimate()`), then check reduced motion and `data-motion` on `<html>`. Content stays visible without JS by design. Scroll parallax needs `animation-timeline: view()` or the runtime fallback. In-app reduce flashes on load — render `<MotionScript />` in `<head>` (same pattern as `IdentityScript`) so `data-motion="reduce"` is set before paint; `useMotionPreference()` is `"reduce"` on the server.

Triggers and tokens

One element can carry several triggers. Identities retune the same tokens (--zk-reveal-duration, --zk-reveal-distance, --zk-reveal-ease, --zk-stagger-step, --zk-lift-*, --zk-press-scale, --zk-longpress-ms).

TriggerAttributeWhen
appeardata-animate / data-animate-appearEnters the viewport once
scrolldata-animate-scrollProgress through the viewport (view() timeline, rAF fallback)
pressdata-animate-press:active (not disabled)
longpressdata-animate-longpressPointer held --zk-longpress-ms
hoverdata-animate-hover:hover on hover-capable pointers
focusdata-animate-focus:focus-visible

Mount <AnimateObserver /> once near the app root so appear, the scroll fallback, and longpress run. Press, hover and focus are CSS-only.

Reduced motion leaves everything visible and still. The attribute grammar and trigger semantics live in packages/ui/docs/animate-spec.md.

On this page