GSAP in Webflow · Pitfalls

Webflow's native Button is wrong for animated controls

Webflow's native Button element renders as an anchor and cannot nest children, which makes it wrong twice over — semantically wrong for anything that performs an action rather than navigating, and structurally useless for the layered hover effects that need an icon or overlay inside.

  • intermediate
  • Last verified: July 27, 2026
  • Verified against: lesson-prose

The symptom

Two different-looking problems with one root:

  • You want to animate an icon inside a button and there is nowhere to put it — Webflow’s Button element won’t accept children.
  • A screen reader announces your “Open dialog” control as a link, and keyboard users find that Space doesn’t activate it.

The cause

Webflow’s native Button element renders as an <a>. It is a styled anchor — navigation, semantically — and it accepts no child elements.

So it is wrong along two independent axes, which is why the corpus rejects it from two different directions and arrives at two different replacements. That looks like a contradiction until you see the question underneath: is this control navigating, or performing an action?

The rule

The control…UseWhy
Goes somewhere — another page, an anchor, an external URLLink blockIt genuinely is a link, and a link block nests children freely
Does something — opens a dialog, toggles a theme, resets a stackCustom element, tag button, type="button"Focusable, activates on Enter and Space, announced as an action
Webflow’s native ButtonneitherAn anchor that can’t nest — wrong semantics and no structure

Both replacements nest children. That is the part people miss: choosing correct semantics does not cost you the layered structure the animation needs.

For animated controls specifically

Layered hover effects need an inner structure — an icon, an overflow: hidden text wrapper, an absolutely-positioned overlay div. All of the micro-interaction patterns in the corpus animate those children:

  • a text wrapper’s width from 0 to auto inside an overflow: hidden parent
  • an overlay sliding from translateX(-101%) to 0
  • an arrow icon rotating inside the button

None of that is possible in Webflow’s Button element. And it connects to a second boundary worth holding onto: Webflow’s hover state styles only the element itself, never its children or siblings — so the moment your effect reaches into a child, you need both a nestable element and a GSAP interaction. See The interactions model — trigger, target, action, timeline.

Don’t forget the labels

An icon-only control has no accessible name. Whichever element you chose:

  • aria-label on the control — close dialog, open join newsletter dialog
  • aria-hidden="true" on the decorative icon inside it

And on a custom button element, set type="button" explicitly. Without it, a button inside a form defaults to submit, and clicking your “open panel” control submits the form instead.

Verify

Tab to the control and press Space. A real button activates; a link does not. Then check what a screen reader announces — “button” versus “link” is the whole difference, and it tells the user whether to expect the page to change.

Sources