Shake animation using CSS
27 Oct 2024

CSS Shake Animation

Here is the code for the shake animation. Attach the shake CSS class to an element and it will do the shake animation. Then we would need to remove the shake class when the animation ends. To do that, we can set a timer to remove it after 820ms, or hook to the animationend event to remove it.

.shake {
  animation: shake 820ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}

@keyframes shake {
  10%,
  90% {
    transform: translate3d(-1px, 0, 0);
  }

  20%,
  80% {
    transform: translate3d(2px, 0, 0);
  }

  30%,
  50%,
  70% {
    transform: translate3d(-4px, 0, 0);
  }

  40%,
  60% {
    transform: translate3d(4px, 0, 0);
  }
}

Shake animation component

Lets go a step further, lets make it a reusable component so we can easily use it.

First lets see how we would use it. One way we can do is expose as a slot prop to trigger the animation.

<template>
  <Shake v-slot="{ triggerShake }">
    <TextInput @on-error="triggerShake()" />
  </Shake>
</template>

Another way is we can expose it as a method from the component to trigger the animation.

<script setup lang="ts">
import Shake from "./Shake.vue";

const shake = ref<InstanceType<typeof Shake>>();

function triggerShake() {
  shake?.triggerShake();
}
</script>

<template>
  <Shake ref="shake">
    <TextInput @on-error="triggerShake()" />
  </Shake>
</template>

Shake.vue component

Here is the Shake Vue component.

<script setup lang="ts">
let element: HTMLElement | null = null;

function setElement(el: HTMLElement) {
  element = el;
}

function triggerShake() {
  if (element) {
    element.classList.add("shake");
  }
}

defineExpose({
  triggerShake,
});
</script>

<template>
  <slot :setElement="setElement" :triggerShake="triggerShake" />
</template>

<style scoped>
.shake {
  animation: shake 820ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}

@keyframes shake {
  10%,
  90% {
    transform: translate3d(-1px, 0, 0);
  }

  20%,
  80% {
    transform: translate3d(2px, 0, 0);
  }

  30%,
  50%,
  70% {
    transform: translate3d(-4px, 0, 0);
  }

  40%,
  60% {
    transform: translate3d(4px, 0, 0);
  }
}
</style>

Demo

Feel free to click the Shake button and watch it shake!

Conclusion

I am always into micro interactions when it comes to UI design and I believe this subtle little Shake animation makes the interaction just a little bit delightful. :)