02UI

Circle fill button

A circle fill button grows a circular fill from where the pointer enters, then covers the control. The press still has to land on the same box.

Buttons and controlsBuild difficulty: Mediumclip-path circle

Also called Radial fill button, Ripple fill, Pointer fill, Circular wipe.

Here it is working.

Hover from different sides. The disc starts where you enter.

For designers

The circle is paint inside a real button. The live Button page still owns the label, hierarchy, loading and the focus ring. Magnetism moves the control. The circle stays inside the clip. The resting fill has to work for thumbs, because there is no pointer to grow from. Origin the circle on the entry point, not the centre every time, or it reads as a canned ripple. A circle that escapes the radius looks like a leak. One of these on a hero can take the extra attention. Four in a row will fight.

When to use circle fill button

Use this when

  • There is one obvious action on a spacious screen, and hover is a real input.
  • You want the fill to admit where someone pointed, without moving the target.
  • The label stays readable as the circle crosses it.
  • Touch and keyboard can use the button with no circle at all.

Reach for something else when

How to build it

Start with a real button. Put a circle behind the label and clip it to the button. On pointer enter, read the position inside the box, place the circle there, and scale it until the button is covered. quickTo helpers keep that from queuing a tween per pixel if you also track move. A 200 to 300 millisecond ease is enough. Leave the hit target where it was. Invert the label as the circle covers it, or pick two fills that both clear 4.5:1. Ignore the effect on touch. Keyboard focus should look like the live Button focus ring. On reduced motion, snap to the hover fill or skip it.

Official GSAP

gsap.to on clip-path, with the circle centred where the pointer entered.

const at = `${pointerX}px ${pointerY}px`;
gsap.set(fill, { clipPath: `circle(0% at ${at})` });
gsap.to(fill, { clipPath: `circle(150% at ${at})`, duration: 0.45, ease: 'power2.out' });

Every plugin ships in the public GSAP package. Nothing here is copied from a paid pack.

Common questions

Is this a ripple?
A ripple is usually a press flash that fades. This is a hover fill that grows from the pointer and stays while you are over the control.
How big does the circle need to be?
Large enough to cover the farthest corner from the entry point.
What about mobile?
Nothing. There is no pointer.
Does the focus ring follow the circle?
No. Keep the ring on the layout box.
Should the circle start from the centre?
Only if you never have a pointer position. From the entry point feels aimed.

Save as skill

A SKILL.md for this one animation: what it is, the official docs link, and a copy-paste block with the reduced-motion branch already in it. Copy gives you the same words.

Use this with your AI

Save the skill, drop it into Cursor, Claude, or whatever you use, and ask for this motion. That is all. The skill tells the agent to open this page, watch the working demo, and match it.

Last reviewed 26 AUG 2026

Next: Curve fill button