How to Master GSAP Interactions in Webflow — Lesson 8
This lesson offers a comprehensive masterclass on engineering a production-ready, fully accessible GSAP-powered popup within Webflow. Moving far beyond basic hide-and-show mechanics, the video provides a rigorous architectural approach to building modals. Viewers will learn how to seamlessly blend technical accessibility standards with elegant, high-performance animations, resulting in a scalable component that can be confidently deployed in professional, real-world projects.
A significant portion of the core value lies in its uncompromising dedication to web accessibility and semantic structure. The lesson demystifies essential ARIA attributes, teaching viewers how to implement role="dialog", aria-modal="true", and aria-labelledby to properly define interaction boundaries for assistive technologies. Furthermore, it highlights the critical difference between navigation and action by demonstrating why custom HTML <button> elements must be used over standard Webflow text links to guarantee native keyboard focus and accurate screen reader announcements.
By the end of the tutorial, viewers will have achieved mastery over advanced UI interactions and robust viewport management. The lesson guides users through crafting a smooth slide and fade-in animation using a single GSAP timeline that can be elegantly reversed to close the modal, completely eliminating redundant animation logic. Additionally, viewers will learn sophisticated UX techniques, including how to lock background page scrolling using GSAP's set actions, handle outside-click detection using custom overlays, consolidate animation triggers using HTML attributes, and utilize dynamic viewport height (100dvh) to ensure flawless rendering across mobile devices.
Key Takeaways
- Establish Explicit Accessibility Contexts: To ensure screen readers interpret popups correctly, developers must define the interaction boundary using
role="dialog"andaria-modal="true", while linking the dialogue to its visible title viaaria-labelledby. - Prioritize Semantic HTML for Actions: Closing a popup is an action, not a navigation event. Using a native HTML
<button>element instead of a styled link ensures the control is focusable by default, triggers correctly with keyboard inputs, and is semantically accurate for assistive technologies. - Utilize Reversible GSAP Timelines: Instead of building separate opening and closing animations, construct a single, clean sequence—setting the display property, fading opacity, and transforming the Y-axis—and simply set the trigger's control property to "reverse" to handle the closing interaction.
- Scale Trigger Logic with HTML Attributes: Rather than targeting multiple individual classes (like a close button and a background overlay), developers can assign a custom HTML attribute (e.g.,
dialog-animation="close") to multiple elements, merging them into a single, highly scalable interaction trigger. - Implement Robust Mobile Viewports & Scroll Locking: Prevent background interactions by using a GSAP set action to instantly change the body's overflow to hidden when the modal opens. To avoid layout shifts caused by dynamic mobile browser UIs, always set the popup wrapper's height to
100dvh(dynamic viewport height) rather than traditionalvh.
Timestamps
- 1:37 - Set the pop-up wrapper element's display property to
flexto begin structuring. - 2:00 - Set the pop-up wrapper's position to
fixedand select thefulloption to anchor it to the viewport. - 2:20 - Set the pop-up wrapper's Z-index to 1,000 to ensure it renders above all other page content.
- 2:33 - Define core accessibility attributes on the pop-up element:
role="dialog",aria-modal="true", andaria-labelledby. - 4:25 - Set the pop-up element's position to
relativeso it can act as the reference element for the absolute-positioned close button. - 4:47 - Create a custom element with the type set to
buttonto ensure native keyboard focus and semantic accuracy for the close button. - 5:37 - Apply the custom
aria-label="close dialog"attribute to the close button so screen readers can interpret the SVG icon. - 6:31 - Embed an SVG icon and set its stroke attribute to
currentcolorso it dynamically inherits the parent element's font color. - 7:14 - Set the pop-up wrapper's display property back to
noneto hide it by default. - 8:36 - Add a GSAP click event interaction to the "Join Newsletter" button.
- 9:50 - Create a GSAP 'set' action to instantly change the target
.popup-wrapperdisplay property fromnonetoflex. - 10:44 - Create a GSAP 'animate' action targeting
.popup-wrapperto build a opacity fade-in from 0%. - 11:42 - Create a GSAP 'animate' action targeting the
.popupclass to build the slide-in animation using a 'from' value of2remon the Y-axis. - 13:03 - Add a click trigger to the close button and set its GSAP control property to "reverse" to dynamically close the popup without duplicate logic.
- 15:02 - Add a new div block inside the wrapper, assign it the class
popup_closing-overlay, and set its position to absolute (full). - 15:47 - Drag the closing overlay element above the pop-up in the navigator panel to correct the DOM stacking order.
- 17:30 - Add the custom HTML attribute
dialog-animation="close"to both the closing overlay and the close button. - 18:00 - Consolidate GSAP logic by changing the trigger's targeting parameter from "class" to "attribute", referencing
dialog-animation="close". - 19:28 - Create a new GSAP 'set' action and target the custom selector
body. - 20:04 - Set the
bodytarget's layout overflow property tohiddento immediately lock background page scrolling. - 21:17 - Explicitly set the pop-up wrapper's height to
100dvh(dynamic viewport height) to prevent layout shifts caused by dynamic mobile browser UIs.
Building Accessible GSAP Popups in Webflow: A Step-by-Step Guide
1. Structuring the Popup Wrapper (1:37 – 2:20)
- How: Select your pop-up wrapper element and temporarily set its display property to
flexwith center alignment. Set the position tofixedand select thefulloption. Finally, set the Z-index to 1,000. - Why: Setting the wrapper to
flexhorizontally and vertically centers the modal perfectly. Using afixedfull position anchors the wrapper to the viewport, removing it from the document flow so it won't move on scroll, while the high Z-index guarantees it sits above all other page content.
2. Defining the Accessibility Context (2:33 – 4:12)
- How: On the inner popup element, navigate to the element settings panel and add three custom attributes:
role="dialog",aria-modal="true", andaria-labelledby="modal-title"(ensuring the value matches the ID of your popup's heading). - Why: These attributes are vital for screen readers.
role="dialog"tells assistive technology this is a new interaction context.aria-modal="true"disables background content interaction. Finally,aria-labelledbyexplicitly links the dialogue to its visible title, providing a clear, accessible name when it opens.
3. Building a Semantic Close Button (4:25 – 7:05)
- How: Set the popup element's position to
relative. Add a custom HTML element inside it with the type set tobutton. Add the attributearia-label="close dialog"to the button. Position itabsolutewith top and right offsets. If using an SVG inside, set the SVG path's stroke tocurrentcolor. - Why: The parent must be
relativeto act as an anchor for theabsoluteclose button. You must use a native HTML<button>rather than a link because closing a modal is an action, not a navigation event; native buttons also accept keyboard focus and enter/space inputs by default. Thearia-labelprovides a readable description of the visual SVG for screen readers, andcurrentcolorcleanly forces the icon to inherit its parent's font color.
4. Building the Opening GSAP Timeline (7:14 – 12:40)
- How: Hide the popup wrapper by setting it back to
display: none. Go to Interactions, target your open button, and create a GSAP click event at 0 seconds. Add a "Set" action targeting the.popup-wrapperclass to changedisplaytoflex. Add an "Animate" action targeting the wrapper to fade opacityfrom0% over 0.8 seconds. Add a final "Animate" action targeting the.popupclass with a move Yfrom2rem. - Why: The animation must be split into three precise actions to work smoothly: the structural injection into the DOM (
Set: flex), the visual reveal (opacity fade), and the movement (move Y). Usingfromvariables dynamically animates the elements into their final, pre-designed Webflow states.
5. Implementing the Close Reversal (12:51 – 13:16)
- How: Select the pop-up close button, add a new click trigger, and under the GSAP properties, change the "control" property to
reverse. - Why: This eliminates duplicate animation logic. By setting it to reverse, GSAP elegantly runs the entire opening timeline backward.
6. Handling Outside Click Detection (14:59 – 16:38)
- How: Inside the popup wrapper, add a new div block (
.popup_closing-overlay) and set its position toabsolute (full). In the Webflow navigator panel, drag this overlay element so it sits above the popup element. Add the same GSAP reverse click trigger to this overlay. - Why: A dedicated full-screen overlay behind the popup correctly intercepts clicks without interfering with form interactions inside the modal. Dragging it above the popup in the navigator fixes the DOM stacking order so the overlay renders behind the popup visually.
7. Merging Triggers via HTML Attributes (17:30 – 18:26)
- How: Add a custom attribute
dialog-animation="close"to both the close button and the closing overlay. In the GSAP interaction panel, change the target of your closing trigger from "class" to "attribute", referencingdialog-animation="close". Delete the redundant second click trigger. - Why: Consolidating multiple elements into a single trigger using an HTML attribute makes the system infinitely cleaner and scalable.
8. Locking Page Scrolling (19:28 – 20:23)
- How: In the open timeline, add a new "Set" action at 0 seconds. Define a custom selector and type
body. Under layout properties, changeoverflowtohidden. - Why: Setting the body's overflow to hidden instantly prevents users from scrolling the background page while the modal is open. Because this is a "Set" action within a reversible timeline, the page automatically unlocks when the closing animation finishes.
9. Ensuring Mobile Viewport Stability (21:14 – 22:19)
- How: Select the popup wrapper and explicitly set its height to
100dvh. - Why: Dynamic viewport height (
100dvh) continuously adjusts to the visible screen, accounting for expanding and collapsing mobile browser UIs (like address bars). Traditional100vhcalculates based on the initial state, which causes glitchy layout shifts and scrolling issues when combined withoverflow: hiddenon mobile browsers.
FAQs
How to lock page scrolling when a popup opens using GSAP?
To lock page scrolling, create a GSAP "set" action triggered when the popup opens. Target the body element using a custom selector and change its CSS overflow property to hidden. This instantly disables background scrolling until the popup interaction is reversed.
Why should I use 100dvh instead of 100vh for mobile overlays?
Using 100dvh (dynamic viewport height) guarantees the overlay adjusts dynamically to the actual visible screen height, accounting for expanding and collapsing mobile browser UIs like address bars. Traditional 100vh calculates based on the initial size, causing overlays to render incorrectly when the browser UI changes.
Should I use a link or a button HTML element to close a modal?
You should strictly use a native HTML <button> element because closing a popup is an action, whereas a link is meant for page navigation. Native buttons are accessible by default, meaning they accept keyboard focus and trigger correctly using keyboard inputs for assistive technology users.
What ARIA attributes are required for an accessible custom popup?
A custom popup requires role="dialog" to identify it as a dialogue window and aria-modal="true" to indicate that background content is not currently interactive. You must also use aria-labelledby referencing the ID of the popup's heading to provide a clear, accessible name for screen readers.