Skip to content
animorio
IT
All components

The menu that opens from its button

Menus, Transitions, TextGSAPMediumCompressed weight: Demo 5.5 KBGSAP 28 KBFreeDownload the zip

A full-screen menu that comes out of its button: a black circle grows from the button until it covers the page, the links rise one after the other, the button turns white, its two lines cross into an X and «Menu» becomes «Close».

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The menu that opens from its button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/syne@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the button stays above the menu: it opens it and, turned white, closes it -->
  <button class="burger" type="button" aria-expanded="false" aria-controls="menu" data-burger data-autoclic>
    <span class="burger__words" aria-hidden="true">
      <span class="burger__word" data-word-open>Menu</span>
      <span class="burger__word" data-word-close>Close</span>
    </span>
    <span class="sr" data-name>Open the menu</span>
    <span class="burger__icon" aria-hidden="true"><i data-line></i><i data-line></i></span>
  </button>

  <!-- the menu: a black circle that grows out of the button until it covers the page -->
  <nav class="menu" id="menu" aria-label="Main" data-menu inert>
    <ul class="menu__links" data-links>
      <li><a class="menu__link" href="#" data-link><span class="menu__mask"><span class="menu__word" data-rise>Work</span></span><svg class="menu__arrow" viewBox="0 0 40 24" aria-hidden="true"><path d="M2 12h34M26 3l10 9-10 9"/></svg></a></li>
      <li><a class="menu__link" href="#" data-link><span class="menu__mask"><span class="menu__word" data-rise>Studio</span></span><svg class="menu__arrow" viewBox="0 0 40 24" aria-hidden="true"><path d="M2 12h34M26 3l10 9-10 9"/></svg></a></li>
      <li><a class="menu__link" href="#" data-link><span class="menu__mask"><span class="menu__word" data-rise>Journal</span></span><svg class="menu__arrow" viewBox="0 0 40 24" aria-hidden="true"><path d="M2 12h34M26 3l10 9-10 9"/></svg></a></li>
      <li><a class="menu__link" href="#" data-link><span class="menu__mask"><span class="menu__word" data-rise>Contact</span></span><svg class="menu__arrow" viewBox="0 0 40 24" aria-hidden="true"><path d="M2 12h34M26 3l10 9-10 9"/></svg></a></li>
    </ul>
    <div class="menu__foot" data-foot>
      <a href="#">Instagram</a>
      <a href="#">LinkedIn</a>
      <a href="#">Dribbble</a>
    </div>
  </nav>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

21 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The menu that opens from its button” from Animorio and fit it into my site

What it does

On a white page there is only a black button in the top right corner, «Menu» with two lines. Pressing it, a black circle grows out of the button until it covers the whole page; meanwhile the button turns white, its two lines meet in the middle and cross into an X with a little bounce, and the word «Menu» rises, leaving its place to «Close». The four links, Work, Studio, Journal and Contact, in a big, wide typeface, rise one after the other out of their masks, leaning 6 degrees, and straighten up; at the bottom three small links appear. Under the pointer the other links fade back and the one pointed at moves 16 pixels right while an arrow draws itself after it. It closes with the button, with Esc or by choosing a link: the links leave upwards and the circle shrinks back into the button.

How it works

The circle

The menu is cut by a clip-path, circle(radius at x y), centred on the middle of the button, with the radius reaching the farthest corner of the window. GSAP moves only the radius, a number, and on every update the clip-path string is written again: closing halfway through an opening starts from where the circle is. The centre is measured again at every opening, every closing and when the window changes.

The links

Each link sits in a mask with overflow: hidden and a little room below for the letters that go down. It starts at yPercent 118 and TILT degrees and reaches zero with power4.out, in RISE[0] seconds, one every RISE[1]; they start when the circle is at 38% of its time. On the way out they rise to −118 in the opposite order.

The button

The two words share one cell of a grid, so the button is as wide as the longer one; one rises and the other comes in from below. The two lines first meet in the middle, in 0.18 seconds, then turn 45 degrees in opposite directions with back.out; on the way back they straighten and then part. The colour changes with a CSS transition.

The link pointed at

A class on the list fades the other links down to DIM; the mask of the one pointed at moves NUDGE pixels and its arrow draws itself: it is a dash as long as the line (getTotalLength), brought back to zero. It works for the mouse and for the Tab key, only when the focus is visible (:focus-visible).

Keyboard and focus

The closed menu is inert. Opened with the keyboard, the focus goes to the first link; opened with a finger or the mouse it stays on the button. The Tab key goes round inside the menu and its button, Esc closes it and the focus goes back to the button. While the menu is open the page under it does not scroll.

Values to change

NameFileDefaultWhat it changes
OPENscript.js0.9The seconds of the circle opening.
CLOSEscript.js0.65The seconds of the circle closing.
RISEscript.js[0.9, 0.07]The links rising: the seconds of each, and the gap between one and the next.
TILTscript.js6The degrees a link leans while it rises.
DIMscript.js0.3How bright the other links stay while one is pointed at.
NUDGEscript.js16The pixels the link pointed at moves right.

Try them in the Playground

When to use it

For a site with few pages and a strong character: a portfolio, a studio, a brand. The full-screen menu gives room to big links; with more than six or seven links a classic menu is better.

On phones

The button is a little smaller and the links narrow to the width of the screen; a tap works like a click. Without a pointer the links do not fade, but the menu opens and closes the same way.

With reduced motion

No circle and no rising links: the menu fades in and out, and the button changes colour, word and lines at once. Under the pointer the other links still fade and the arrow appears without drawing itself.

Pitfalls

  • Between «circle(0px at 100% 0%)» and «circle(1500px at 1200px 40px)» GSAP would interpolate number by number, the centre too, and the circle would travel across the page: that is why only the radius is animated and the string is written by hand.
  • The circle’s centre must be measured when the menu opens: measured only once at the start, after the window changes the circle would start from the wrong place.
  • Opened with the keyboard, the focus must go into the menu and back to the button when it closes. Opened with a finger, it must not: Safari on iPhone would draw the focus ring on the first link, as if the keyboard were in use.
  • The links’ masks keep some room below (a padding with an equal negative margin): without it, the letters that go below the line, like the J, are cut.

Libraries

GSAP 3.15.0, Syne (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 5.5 KB; the libraries: GSAP 28 KB.

Testing

Tested on 2 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: Done

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All components