New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

animate-presence

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

animate-presence

Effortless element entrance/exit animations

  • 0.2.1
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
123
increased by57.69%
Maintainers
1
Weekly downloads
 
Created
Source
Animate Presence

Effortless element entrance/exit animations.

GitHub  /  NPM  /  Examples



Unlike most animation libraries, there's no new API to learn—just use CSS or the Web Animations API.

Here's a basic example using CSS. See Declarative Animations.

<animate-presence>
  <div class="item">Item A</div>
  <div class="item">Item B</div>
  <div class="item">Item C</div>
</animate-presence>

<style>
  .item[data-enter] {
    animation: fade 1s ease-in;
  }
  .item[data-exit] {
    animation: fade 1s ease-out reverse;
    animation-fill-mode: both;
  }
  @keyframes fade {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
</style>

Here's a basic example using WAAPI. See Imperative Animations.

import { createPresenceHandler } from 'animate-presence';

const List = () => {
  const fade = new Animation({
    opacity: [0, 1],
  });
  const handleEnter = createPresenceHandler(async el => {
    return el.animate(fade, {
      duration: 1000,
      easing: 'ease-in',
      fill: 'both',
    });
  });
  const handleExit = createPresenceHandler(async el => {
    return el.animate(fade, {
      duration: 1000,
      easing: 'ease-out',
      direction: 'reverse',
      fill: 'both',
    });
  });
  return (
    <animate-presence
      onAnimatePresenceEnter={handleEnter}
      onAnimatePresenceExit={handleExit}
    >
      <div class="item">Item A</div>
      <div class="item">Item B</div>
      <div class="item">Item C</div>
    </animate-presence>
  );
};

Declarative Animations (CSS)

As child elements are added or removed, data-enter and data-exit attributes are automatically applied.

Using CSS, you can use these attributes as hooks to apply an animation or transition.

Once the animation finishes, <animate-presence> automatically cleans itself up, removing the attribute and any listeners.

Attributes

AttributeDescription
data-enterApplied immediately when a node enters. Trigger your entrance animation here.
data-exitApplied when a node will be removed. Trigger your exit animations here. The node will be removed when the animation completes.

Note Animate Presence overrides the default animation-fill-mode of animating children to both (rather than none). This provides more reasonable default behavior in most situations, so the rule is injected with a specificity (021) high enough to override the animation shorthand for most rules (like .item[data-enter]).

If you experience visual flickering at the start or end of an animation, you may be using a selector with a higher specificity than 021. The animation shorthand resets the animation-fill-mode to none, so you likely need to manually specify both.

Stagger

When multiple elements enter/exit, Animate Presence automatically sets a custom property, --i, on each child.

This makes staggered animations simple with a small calc function.

[data-enter] {
  animation-delay: calc(var(--i, 0) * 50ms);
}

Imperative Animations (WAAPI)

Using the Web Animations API to imperatively animate entrances/exits is the best way to coordinate complex, multi-step animations.

It's also possible to use your favorite animation library, like Popmotion or Anime.js!

Events

EventDescription
animatePresenceEnterDispatched immediately when a node enters. Handle your entrance animation here.
animatePresenceExitDispatched when a node will be removed. Handle your exit animations here. The node will be removed when the handler returns.

As you might expect, these events are dispatched to the children of animate-presence as they enter or exit. These events bubble, so listeners can be attached directly to an animate-presence element via addEventListener or onAnimatePresenceEnter/Exit handlers.

createPresenceHandler

Use the included createPresenceHandler utility to create async callbacks for these events.

import { createPresenceHandler } from 'animate-presence';

const onExit = createPresenceHandler(async (el, { i }) => {
  // Note that `element.animate()` doesn't return a Promise, it returns an `Animation`.
  // In order to await the `Animation`, you want `Animation.finished`.
  await el.animate(
    [{ transform: 'translateY(0)' }, { transform: 'translateY(50%)' }],
    {
      duration: 300,
      delay: i * 50,
      easing: 'cubic-bezier(0.165, 0.84, 0.44, 1)',
      fill: 'both', // Be sure to set this!
    }
  ).finished;

  // `createPresenceHandler` can optionally `return el.animate()` instead of using `await el.animate().finished`
  await el.animate(
    [
      { opacity: 1, transform: `translate(0, 50%)` },
      { opacity: 0, transform: `translate(16px, 50%)` },
    ],
    {
      duration: 300,
      easing: 'cubic-bezier(0.165, 0.84, 0.44, 1)',
      fill: 'both', // Be sure to set this!
    }
  ).finished;
});

const ap = document.querySelector('animate-presence');
ap.addEventListener('animatePresenceExit', onExit);

Nesting

Animate Presence uses a tree-based approach, meaning that nested animate-presence elements are aware of their parents and children.

Enter animations are applied top-down, meaning the top-level parent enters, which triggers the next child entrance, and so on.

Exit animations are applied bottom-up, meaning the deepest child exits, which triggers the next parent exit, and so on.

Animate Presence relies on querySelectorAll to construct the internal tree, so it does not (yet) work with Shadow Roots. This is an area I'm actively looking into.

Usage with @stencil/router

For Stencil apps using @stencil/router, Animate Presence has an <animated-route-switch> component which allows you to smoothly animate between routes.

  1. Swap your <stencil-route-switch> component with <animated-route-switch>

  2. Due to a current bug in @stencil/router, you will need to use injectHistory to pass location down to animated-route-switch.

    Hopefully this will be fixed soon, but there's a simple work around for now.

import { Component, h, Prop } from '@stencil/core';
import { injectHistory, LocationSegments } from '@stencil/router';

@Component({
  tag: 'app-root',
  styleUrl: 'app-root.css',
  scoped: true,
})
export class AppRoot {
  @Prop() location: LocationSegments;

  render() {
    return (
      <div>
        <header>
          <h1>Stencil App Starter</h1>
        </header>

        <main>
          <stencil-router>
            {/* Pass `location` to animated-route-switch */}
            <animated-route-switch location={this.location}>
              {/* <animate-presence> should exist somewhere within these components */}
              <stencil-route url="/" exact={true} component="app-home" />
              <stencil-route url="/profile/:name" component="app-profile" />
            </animated-route-switch>
          </stencil-router>
        </main>
      </div>
    );
  }
}
injectHistory(AppRoot);
  1. Apply your animations on [data-enter] and [data-exit] as usual.

As noted above, if your Stencil components rely on shadow encapsulation, Animate Presence won't work as expected (yet). I'm working on it. For now, you can either use scoped encapsulation or stay tuned for updates!

FAQs

Package last updated on 29 Feb 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc