Get Started with the Template

Quick Setup

Add these scripts to your Webflow project's Custom Code section (Project Settings > Custom Code > Before </body> tag).

1. Expandable Blog Cards

This animation creates an interactive expandable blog card layout for the blog section. On larger screens, hovering over a blog card expands it while collapsing the others. It also reveals the description and read-more button with a smooth GSAP transition.

What it does

  • Expands the hovered blog card
  • Collapses the previously active card
  • Reveals blog description and read-more button for the active card
  • Applies image filter transitions for active/inactive states
  • Adds entrance animation to the section subtitle, title, button, and cards
  • Automatically disables the effect on tablet and mobile devices

Device support

Desktop only (992px and above)

This interaction is automatically disabled on:

  • Tablet
  • Mobile landscape
  • Mobile portrait

On smaller screens, all cards return to their normal/default layout without GSAP width animation.

Required HTML structure

Example:

.blog-section
  └─ .home-blog-flex-box
      ├─ .blog-card-wrapper.active
      │   └─ .home-blog-list-card
      │       ├─ .home-blog-thumbnile-block
      │       │   └─ .blog-thumbnile
      │       └─ .home-blog-list-content-block
      │           └─ .home-blog-list-content-inner
      │               └─ .home-blog-title-and-description-wrap
      │                   ├─ .home-blog-title
      │                   ├─ .home-blog-description-block
      │                   └─ .home-read-more-button-block
      │                       └─ .button-hover-line
      ├─ .blog-card-wrapper
      ├─ .blog-card-wrapper
      └─ .blog-card-wrapper

Required class names

These class names are required for the script to work properly:

Main wrappers

  • .blog-card-wrapper — each blog card item
  • .blog-card-wrapper.active — default active card on page load

Card content

  • .home-blog-description-block — hidden/revealed description area
  • .home-read-more-button-block — hidden/revealed CTA area
  • .home-blog-title — animated title
  • .blog-thumbnile — blog image that receives filter transition
  • .button-hover-line — animated line under the link button

Section intro animation

  • .section-subtitle
  • .section-title
  • .secondary-button

How it works

Default state

When the page loads on desktop:

  • the card with .active class becomes expanded
  • all other cards stay collapsed
  • only the active card shows its description and read-more button

Hover interaction

When a user hovers over another card:

  • previously active card shrinks
  • new hovered card expands
  • previous card content hides
  • new card content becomes visible
  • image filter updates for both cards
  • title and hover line animate in

Resize behavior

When screen size goes below 992px:

  • all width animations are removed
  • hidden content is collapsed
  • desktop interaction is disabled automatically

When resizing back to desktop:

  • the section re-initializes again

Initial active card

To set the first expanded card on page load, add the class:

active

Example:

<div class="blog-card-wrapper active">

Only one card should have the .active class initially.

GSAP requirements

Make sure GSAP is loaded in your Webflow project before this script runs.

If your project uses only core GSAP features from this snippet, standard GSAP is enough.

Since this blog card animation does not use Draggable, GSAP Draggable is not required for this section.

Recommended CSS setup

For smoother animation, make sure these elements can animate cleanly in your CSS/Webflow styles:

Blog description and CTA

Set these elements so hidden content does not overflow:

  • .home-blog-description-block
  • .home-read-more-button-block

Recommended behavior:

  • overflow: hidden
  • default hidden state supported by max-height and opacity

Card layout

For best results:

  • parent .home-blog-flex-box should use a horizontal layout
  • .blog-card-wrapper should sit side-by-side
  • widths should not be hard-locked in a conflicting way on desktop

Customization options

You can easily change the animation behavior by editing these values in the script:

Card widths

var ACTIVE_WIDTH = "40%";
var INACTIVE_WIDTH = "20%";

Animation speed

var DURATION = 0.65;

Easing

var EASE = "power3.inOut";

Desktop breakpoint

var TABLET_BP = 992;

If you want the effect to start only on larger desktop screens, increase the breakpoint.If you want to include tablet landscape, lower the breakpoint carefully.

Important notes

  • This interaction is hover-based, so it is intended for desktop devices
  • Do not remove the required class names unless you also update the script
  • Only one card should be marked as .active on initial load
  • If no card has .active, the section may not show the intended default expanded state
  • This script is written as a class-based setup only and does not require data attributes

Troubleshooting

Animation not working

Check the following:

  • GSAP is loaded correctly
  • script is placed before </body>
  • class names match exactly
  • at least one .blog-card-wrapper exists
  • one card has the .active class initially

Cards are not expanding

Make sure:

  • screen width is 992px or above
  • no conflicting Webflow interaction or CSS width rule is overriding GSAP

Description or button is always visible

Make sure:

  • .home-blog-description-block and .home-read-more-button-block are not forced open by CSS
  • overflow is hidden where needed

Mobile layout looks broken

This script already disables desktop interaction on smaller screens, but your mobile/tablet layout should still be designed separately inside Webflow.

Summary

This expandable blog card animation is designed to create a more interactive blog showcase on desktop screens. It highlights one card at a time, reveals more content on hover, and keeps the mobile/tablet experience clean by disabling the effect below 992px.

How to Update Variables

  1. Open your project in Designer.
  2. Access the Variables panel:
    • Select the Variables icon in the Style panel (the small circle with a dot).
    • Or press Shift + Cmd/Ctrl + M to open the Style Manager and switch to the Variables tab.
  3. Browse your variable groups such as color and typography. You’ll find items like --Primary Color or --Heading Font Size.
  4. Select any variable to change its value.
    Once updated, the change applies instantly across all elements that use that variable.
  5. Optional:
    You can still adjust colors or typography on individual elements directly from the Style panel if you prefer not to rely on variables.

How to Update Text and Images

Updating Text

  1. Select the text element on the canvas.
    Click once to highlight the text field.
  2. Enter edit mode.
    Click again or press Enter to start editing.
  3. Type your new content.
    You can add, remove, or rewrite anything directly in place.
  4. Apply styling if needed.
    Use the Style panel to adjust font, size, color, spacing, or any typography settings for that element.

Updating Images

  1. Click the image you want to replace.
    This selects the image element on the canvas.
  2. Open the Settings panel.
    Use the gear icon in the right sidebar to access image options.
  3. Choose “Replace Image.”
    This opens your asset selection window.
  4. Upload a new file from your computer or select an existing image from the Assets panel.
  5. The new image updates instantly across the canvas.
    If that image is used in multiple places (via Components or Symbols), those instances update as well.

How to Replace an Icon (SVG)

  1. Select the icon element on the canvas.
    This highlights the Embed block that contains your current SVG code.
  2. Open the Embed editor.
    Click Edit Embed in the small toolbar that appears above the element or in the Settings panel.
  3. Remove the existing SVG markup.
    You’ll see code that looks like <svg>…</svg>. Select and delete it.
  4. Paste your new SVG code.
    Insert the full markup for your new icon, starting with <svg> and ending with </svg>.
  5. Save your changes.
    Click Save & Close to update the element.
  6. Your icon refreshes immediately on the canvas, and if it's used inside a Component, all linked instances update automatically.

How to Adjust Animations

  1. Select the element that contains the animation.
    Click it on the canvas to highlight the interaction connected to it.
  2. Open the Interactions panel using the ⚡ icon in the right sidebar.
    This panel shows all triggers and actions applied to the selected element.
  3. Choose the interaction you want to edit.
    You can adjust scroll, click, hover, load, or other triggers linked to that element.
  4. Update the animation settings.
    Change easing, timing, movement values, opacity, scale, or any other properties included in the action list.
  5. Preview the result.
    Use the eye icon in the panel to test how the interaction behaves before publishing.

How to Update Page SEO

  1. Open the Pages panel from the left sidebar.
  2. Find the page you want to edit and click the gear icon beside its name to open Page Settings.
  3. Scroll to the SEO section and update the following fields:
    • SEO Title
    • Meta Description
    • Open Graph Image
  4. Save your changes. These details improve visibility on search engines and control how your page appears when shared.
  • Open Page Settings or Custom Code from site setting → Before </body> tag or footer code.
  • Paste the code bellow:
<script>

// counter animation

window.Webflow = window.Webflow || [];
window.Webflow.push(function () {
  const counters = document.querySelectorAll(".counter-animate");

  function runCounter(el) {
    let raw = el.textContent.trim();
    let numeric = raw.replace(/[^0-9.,-]/g, "").replace(/,/g, "");
    let target = parseFloat(numeric);
    if (isNaN(target)) return;

    let decimals = (numeric.split(".")[1] || "").length;
    let duration = parseFloat(el.getAttribute("data-duration")) || 2;

    let obj = { value: 0 };
    el.textContent = (0).toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ",");

    gsap.to(obj, {
      value: target,
      duration: duration,
      ease: "power1.out",
      onUpdate: () => {
        el.textContent = obj.value
          .toFixed(decimals)
          .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
      }
    });
  }

  // Intersection Observer for all counters in the viewport
  let observer = new IntersectionObserver(entries => {
    // Collect all visible counters
    let visibleCounters = [];
    entries.forEach(entry => {
      if (entry.isIntersecting) visibleCounters.push(entry.target);
    });

    if (visibleCounters.length) {
      // Animate counters **staggered**
      visibleCounters.forEach((el, i) => {
        setTimeout(() => runCounter(el), i * 300); // 300ms stagger
        observer.unobserve(el); // Only run once
      });
    }
  }, { threshold: 0.2 });

  counters.forEach(el => observer.observe(el));
});
</script>
  • Select any heading or text block.
  • Wrap only the number portion of the text in a <span>.
  • Add the class name "Counter Animate" to that span.

Use the data-duration attribute to adjust the counter animation duration.

Start Your Trial Today

First Class Free

Start Your Trial Today

First Class Free

Start Your Trial Today

First Class Free

Start Your Trial Today

First Class Free

Start Your Trial Today

First Class Free

Start Your Trial Today

First Class Free