Last week we continued a teardown of the wonderful animations in Stripe Checkout and took a deep dive into the modal shake animation used for form validation. This week we will take a look at one of the ways that animations are harnessed for form submission.


Before diving into the CSS that comprises this animation, let's look at why this is a good use of CSS animations. Primarily this is an optimal user experience when there is an asynchronous action happening that may take longer than the user expects (in this case sending a text notification could be on the order of seconds). This animation is not tied to the actual progress, but instead is a placeholder for what would otherwise be a loading state that would last for more than a second. Jakob Nielsen digs in here and reasons that the typical user's flow of thought is around 1 second. This is significant for a flow such as Stripe Checkout where the user is trying to purchase something, and the use of animation here does a good job at keeping the user engaged.


This is a relatively straightforward effect to implement given the animation rules we have learned in the past couple weeks. The animation here makes use of two animation rules: translation and transition. The content is set up to be all in the same block, there is a pre-transition state where the content is below the button and a post-transition state where the content is above the button.

We will manipulate the Y axis of the content during the transition and have it fade in and out of view using the opacity of the element. The above picture displays the two transitions we will have, there will be one element that will fade in and slide up (1) and another element in view that will fade out and slide up (2).

The two pieces of content can be placed into the button.

<button class="submit">
  <span class="hello-container">
    <p class="hello-text">Hello!</p>
  <span class="goodbye-container">
    <p class="goodbye-text">Goodbye!</p>

And we can have the CSS set the initial state of hidden elements to be below the fold of the button.

.goodbye-container {
  -webkit-transform: translateY(10px);
  opacity: 0;

The transition will ease out and have two rules to transition: a transform and opacity. These give us the ability to fade as well as translate:

.slide-out {
  transition: all 400ms ease-out;
  -webkit-transform: translateY(-10px);
  opacity: 0;

.slide-in {
  transition: all 400ms ease-out;
  -webkit-transform: translateY(0px);
  opacity: 1;

After applying this, it is simple enough to bind an event listener that applies the sliding out to the current content and sliding in to the next content in line to get the effect:

This is a part of the Dissecting Delight series, we initially will be reviewing the Stripe Checkout animations and hopefully many more great experiences. The code is available on Github here, please feel free to make poke me on Twitter if there's anything I can help with or correct!