Skip to main content

Live demo

Pulse animations create a rhythmic breathing effect by combining scale and opacity changes. They’re perfect for drawing attention to notifications, live indicators, and interactive elements without being overly distracting.
Pulse animations should be subtle and slow to avoid causing fatigue or motion sickness.

Complete code example

import { motion } from 'framer-motion'

export default function PulseDemo() {
  return (
    <div className="space-y-8">
      {/* Basic pulse */}
      <motion.div
        animate={{
          scale: [1, 1.2, 1],
          opacity: [1, 0.8, 1]
        }}
        transition={{
          duration: 2,
          repeat: Infinity,
          ease: 'easeInOut'
        }}
        className="w-24 h-24 bg-red-500 rounded-full mx-auto"
      />

      {/* Ring pulse */}
      <div className="relative w-24 h-24 mx-auto">
        <div className="absolute inset-0 bg-blue-500 rounded-full" />
        <motion.div
          animate={{
            scale: [1, 2],
            opacity: [0.6, 0]
          }}
          transition={{
            duration: 1.5,
            repeat: Infinity,
            ease: 'easeOut'
          }}
          className="absolute inset-0 bg-blue-500 rounded-full"
        />
      </div>
    </div>
  )
}

How it works

Pulse animations combine multiple properties:
1

Scale oscillation

The element grows and shrinks rhythmically between its normal size and a slightly larger size.
2

Opacity fade

Opacity changes subtly to enhance the breathing effect.
3

Smooth easing

Use ease-in-out for smooth transitions that feel organic.

Pulse variations

Basic pulse

Simple scale and opacity oscillation

Ring pulse

Expanding ring that fades out (ping effect)

Glow pulse

Shadow or blur expanding and contracting

Color pulse

Background or border color shifting

Variations

Live indicator

Perfect for showing live status:
import { motion } from 'framer-motion'

function LiveIndicator() {
  return (
    <div className="flex items-center gap-2">
      <div className="relative">
        <motion.div
          animate={{
            scale: [1, 1.5],
            opacity: [0.7, 0]
          }}
          transition={{
            duration: 1.5,
            repeat: Infinity,
            ease: 'easeOut'
          }}
          className="absolute w-3 h-3 bg-red-500 rounded-full"
        />
        <div className="relative w-3 h-3 bg-red-500 rounded-full" />
      </div>
      <span className="text-sm font-medium">LIVE</span>
    </div>
  )
}

Notification badge

Attention-grabbing badge pulse:
import { motion } from 'framer-motion'

function NotificationBadge({ count }) {
  return (
    <motion.div
      animate={{
        scale: [1, 1.2, 1]
      }}
      transition={{
        duration: 1,
        repeat: Infinity,
        repeatType: 'reverse'
      }}
      className="w-6 h-6 bg-red-500 text-white text-xs rounded-full flex items-center justify-center"
    >
      {count}
    </motion.div>
  )
}

Breathing card

Subtle pulse for emphasis:
import { motion } from 'framer-motion'

function BreathingCard() {
  return (
    <motion.div
      animate={{
        scale: [1, 1.02, 1],
        boxShadow: [
          '0 4px 6px rgba(0,0,0,0.1)',
          '0 8px 12px rgba(0,0,0,0.15)',
          '0 4px 6px rgba(0,0,0,0.1)'
        ]
      }}
      transition={{
        duration: 3,
        repeat: Infinity,
        ease: 'easeInOut'
      }}
      className="p-6 bg-white rounded-lg"
    >
      Featured Content
    </motion.div>
  )
}

Multi-ring pulse

Multiple expanding rings:
import { motion } from 'framer-motion'

function MultiRingPulse() {
  return (
    <div className="relative w-16 h-16">
      <div className="absolute inset-0 bg-purple-500 rounded-full" />
      {[0, 0.3, 0.6].map((delay, i) => (
        <motion.div
          key={i}
          animate={{
            scale: [1, 2.5],
            opacity: [0.5, 0]
          }}
          transition={{
            duration: 2,
            repeat: Infinity,
            delay,
            ease: 'easeOut'
          }}
          className="absolute inset-0 bg-purple-500 rounded-full"
        />
      ))}
    </div>
  )
}

Example from the playground

From the CSSAnimations component:
const presets = {
  pulse: `
.animated-element {
  width: 100px;
  height: 100px;
  background: linear-gradient(45deg, #FF6B6B, #4ECDC4);
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.2); opacity: 0.8; }
  100% { transform: scale(1); opacity: 1; }
}`,
}

Best practices

Pulse animations should be noticeable but not distracting. Use small scale changes (1-1.2).
// Good - subtle pulse
scale: [1, 1.1, 1]

// Too aggressive
scale: [1, 2, 1]
Slower pulses (2-3 seconds) feel more natural and less jarring.
transition={{ duration: 2.5, repeat: Infinity }}
Mixing scale with opacity or shadow creates richer effects.
animate={{
  scale: [1, 1.1, 1],
  opacity: [1, 0.8, 1],
  boxShadow: ['0 0 0 rgba(0,0,0,0)', '0 0 20px rgba(0,0,0,0.2)', '0 0 0 rgba(0,0,0,0)']
}}
Disable pulse animations for users who prefer reduced motion.
const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
).matches

const animate = prefersReducedMotion ? {} : { scale: [1, 1.1, 1] }

Common use cases

  • Live status indicators
  • Notification badges
  • Recording indicators
  • Loading states
  • Call-to-action emphasis
  • Online/active status
  • Alert signals
  • Microphone/camera active indicators

Performance tips

Pulse animations using scale and opacity are GPU-accelerated. Avoid pulsing other properties like width, height, or border-width.
// Good - GPU accelerated
<motion.div animate={{ scale: 1.1, opacity: 0.8 }} />

// Avoid - forces repaints
<motion.div animate={{ width: 120, borderWidth: 5 }} />

Accessibility considerations

Pulse animations can be distracting for some users:
  • Keep animations slow (2+ seconds)
  • Limit number of pulsing elements on screen
  • Provide option to disable animations
  • Respect prefers-reduced-motion system setting
  • Don’t pulse rapidly (< 1 second) as it can trigger seizures

Scale

Scale transform animations

Bounce

Bouncing motion effects

Fade in

Opacity transitions

Build docs developers (and LLMs) love