Hover✨ Premium

Morph on Click

A div morphs its shape on each click via CSS clip-path transition: circle, diamond, rounded rect, triangle, back to circle — 5 shapes, infinite loop.

CSSJSTransform

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →

3 usage examples

Format selector in an editorial tool — writing interface of a media startup — Morph on Click example 1

① Format selector in an editorial tool — writing interface of a media startup

WhenEach click changes the icon's shape (circle = short post, diamond = long article, rectangle = video, triangle = thread) to indicate the chosen content type, without text.
WhyA shape change encodes content type without extra text; it is a UI convention directly inspired by social media iconography.
Settings80×80 px shape. Colour also changes per shape (add a CSS class per index). Hover tooltip to show the format name.
Geometry exercise — Year 2 maths module in a tutoring app — Morph on Click example 2

② Geometry exercise — Year 2 maths module in a tutoring app

WhenThe pupil clicks the shape to change its figure (circle → diamond → rectangle → triangle) and learns to name geometric shapes.
WhyA shape that transforms on click is a fun, hands-on geometry recognition exercise — more engaging than a static image.
Settings160×160 px shape, vivid coloured background. Text label below that changes with the shape ("Circle", "Diamond"…) via JS. Transition speed raised to 0.8 s for a contemplative look.
Dashboard view toggle — attendance analysis tool for a university library — Morph on Click example 3

③ Dashboard view toggle — attendance analysis tool for a university library

WhenA single morphing button changes shape according to the active view: circle = pie chart, diamond = bar chart, rectangle = table.
WhyOne morphing button takes less space than a group of three view buttons in a compact header — and creates a visually satisfying state-change animation.
Settings48×48 px shape in the header. Fast transition (0.3 s). Active shape highlighted by an accent colour (background-color also changed via JS).

How it works

The .fx-0376-root frame holds a .mph-shape element with tabindex="0" role="button" and a descriptive label. The script keeps a current index per instance (JavaScript closure — two instances on the same page are independent). On load, the index is 0 (circle) and the shape's clip-path is set to the circle value.

On click (or keydown Enter/Space), the index is incremented modulo 5 and clip-path is updated. The 5 shapes are defined as CSS clip-path values: circle (circle(50%)), diamond (polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)), rounded rectangle (inset + radius), triangle (polygon(50% 0%, 100% 100%, 0% 100%)). The CSS transition (clip-path 0.5s ease) interpolates the polygons: all shapes having the same number of points, the morphing is smooth.

Under prefers-reduced-motion: reduce, the transition is suppressed (transition: none !important): shapes change instantly on click. The functional effect (shape change) is preserved; only the animation is disabled.

Accessibility

  • Keyboard: the element is focusable by Tab (tabindex="0") and announced as a button (role="button"). Enter and Space trigger the shape change.
  • Reduced motion: under prefers-reduced-motion: reduce, the shape change is instant — no transition. The functional behaviour is preserved.
  • Shape label: the element carries a static aria-label ("Shape — click to transform"). To inform assistive technologies of the active shape, add a dynamic aria-label updated on each click: "Circle — click to change shape".
  • No information encoded visually: if the active shape carries meaning (circle = type A, diamond = type B…), that information must also be conveyed through visible text or an updated aria-label — shape alone is not enough for screen reader or keyboard navigation users.

Browser compatibility

CSS clip-path + 1 KB of JavaScript, no dependency. clip-path: polygon() available since Chrome 55, Firefox 54 and Safari 10. CSS transition on clip-path available since Chrome 55, Firefox 72 and Safari 13.1 — on Firefox 54-71, shape change is instant (no animated morphing). Measured in Chromium 151, Firefox 153 and WebKit 26: all transitions smooth in all three.

Chrome 55+✓ Full (animated morphing)
Firefox 72+✓ Full (animated morphing)
Safari 13.1+✓ Full (animated morphing)
Edge 79+✓ Full (animated morphing)
Mobile iOS 13.4+✓ Full
Android Chrome 55+✓ Full

Without JavaScript, the element shows the initial shape (circle) without changing on click. On Firefox 54-71 (outside current scope), clip-path works but the transition is not animated: shapes change instantly.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0376-root">
  <div class="mph-shape" tabindex="0" role="button" aria-label="Shape — click to transform">CLICK ME</div>
  <span class="mph-label" aria-hidden="true">Click to transform</span>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Shapes (CSS — clip-path arrays in JS) circle, diamond, rounded rectangle, triangle, (back to circle) — 5 shapes Add or remove shapes in the JS array. For smooth morphing, all shapes must have the same number of polygon points; convert the circle and rounded rectangle to N-point polygons (where N is the point count of your most complex shapes).
Transition duration (CSS — transition: clip-path 0.5s ease) 0.5 s Lower to 0.2 s for a snappy change; raise to 1 s for a slow transformation.
Shape colour (CSS — background-color of .mph-shape) violet (#7c3aed) Add a transition on background-color and change the colour in JS per index to give each shape its own tint.
Shape size (CSS — width and height of .mph-shape) 120×120 px Adjust freely. For a non-square aspect (elongated diamond, wide triangle), adapt the clip-path values accordingly.
Trigger (JS — events) click + keyboard Enter/Space To trigger on hover instead of click, replace click with mouseenter. For automatic cycling, use setInterval.

FAQ

Yes. Add clip-path values to the JS array. For smooth morphing, each shape must have the same number of points; convert the circle and rounded rectangle to N-point polygons (where N is the point count of your most complex shapes).
clip-path: circle(50%) and clip-path: polygon(...) are different value types; the browser cannot interpolate them directly. To animate between a circle and a polygon, express the circle as an N-point polygon uniformly distributed on a circle (clip-path: polygon(50% 0%, 60% 10%, ...)).
Store the current index in localStorage: localStorage.setItem('mph-idx', idx) on each click, and read parseInt(localStorage.getItem('mph-idx') || '0') on load. Wrap accesses in try/catch since localStorage can be blocked in private browsing.