Skip to main content

Command Palette

Search for a command to run...

How to make a small pulsating animation

How to create a new animation for Tailwind and use it in your Rails app

Updated
3 min read
How to make a small pulsating animation

The other day, I added a deals page to the GoodEnoughTesting website and considered making the menu item a bit more visible. I wanted it to pulsate just a bit, without being too much.

Tailwind already has an animation called pulse, but I wanted something else. I wanted something that would scale a bit and then come back.

This is what I implemented:

First, I added the following in the application.tailwind.css where I define a 3 keyframes, and I scale it just a bit over at 50% (or the middle frame):

@keyframes pulsate {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.10);
  }
  100% {
    transform: scale(1);
  }
}

Then I extended Tailwind to include this as animation, by adding the following in the config/tailwind.config.js:

module.exports = {
  theme: {
    extend: {
+      animation: {
+        'pulsate': 'pulsate 2s ease-in-out infinite',
+      }
    },
  },
}

And now I can use it in the header menu:

<a href="" class="motion-safe:animate-pulsate"> 
  A pulsating link 
</a>

I used motion-safe modifier to respected the choice of the user if they requested reduced motion.

Extracting a component

I am using Phlex when building the UI for the GoodEnoughTesting so I want to extract the menu item to a series of components that I can re-use when needed.

First I created a Menu::ItemComponent:

module Menu
  class ItemComponent < ApplicationComponent
    include Phlex::Rails::Helpers::LinkTo

    CLASS = <<~DEFAULT
      inline-block
      no-underline
      font-bold text-base uppercase leading-6 antialiased
      x-2.5 py-2 px-2
      align-baseline
      hover:bg-blue-200 hover:rounded-lg
    DEFAULT

    def initialize(url:, text: nil, pulsate: false, text_color: "", **options)
      @text = text
      @url = url
      @options = options
      @pulsate = pulsate
      @text_color = text_color
    end

    def template(&)
      if @text.present?
        link_to(@text, @url, class: css_rules)
      else
        link_to(@url, class: css_rules, &)
      end
    end

    private

      def css_rules   = "#{CLASS} #{pulsate_css} #{@text_color}"
      def pulsate_css = (@pulsate ? "motion-safe:animate-pulsate" : "")
  end
end

And then I created simple versions of this component.

Menu::PrimaryComponent is the normal menu item, with a dark gray color:

module Menu
  class PrimaryComponent < ItemComponent
    def initialize(url:, text: nil, **options)
      pulsate = false
      text_color = "text-gray-800"

      super(url:, text:, pulsate:, text_color:, **options)
    end
  end
end

Menu::BlueComponent is a menu item with the blue text:

module Menu
  class BlueComponent < ItemComponent
    def initialize(url:, text: nil, **options)
      pulsate = false
      text_color = "text-blue-700"

      super(url:, text:, pulsate:, text_color:, **options)
    end
  end
end

Menu::PulsatingComponent is the one that is setting the pulsate attribute:

module Menu
  class PulsatingComponent < ItemComponent
    def initialize(url:, text: nil, **options)
      pulsate = true
      text_color = "text-blue-700"

      super(url:, text:, pulsate:, text_color:, **options)
    end
  end
end

And then at the end I combine them inside an ERB file like this:

<%= render Menu::PrimaryComponent.new(url: page_path("articles"), text: "Articles and News") %>
<%= render Menu::PulsatingComponent.new(url: page_path("deals"), text: "Deals", pulsate: true) %>
<%= render Menu::PrimaryComponent.new(url: page_path("about"), text: "About") %>
<%= render Menu::PrimaryComponent.new(url: page_path("contact"), text: "Contact") %>
<%= render Menu::BlueComponent.new(url: participants_sign_in_path, text: "Login") %>

If you like this article:

👐 Join my live workshop about goodenoughtesting.com - to learn test design techniques for writing effective tests

👉 Join my Short Ruby Newsletter for weekly Ruby updates from the community and visit rubyandrails.info, a directory with learning content about Ruby.

🤝 Let's connect on Bluesky, Ruby.social, Linkedin, Twitter where I post mostly about Ruby and Ruby on Rails.

🎥 Follow me on my YouTube channel for short videos about Ruby/Rails

More from this blog

All about code - Ruby and Rails technical content written by Lucian Ghinda

102 posts

I write here quick thoughts, ideas, tips, and learnings about programming, programmers, and building software. Most of my focus is on Ruby, Rails, Hotwire, and everything about web applications.