MD3
Expressive
MATERIAL DESIGN 3 EXPRESSIVE

Shapes

Expressive shape system from Material Design 3. Render organic, smooth-cornered polygons as CSS clip-paths or inline SVG paths with built-in spring-based morphing.

Material Design 3 Expressive shapes utilize a specialized shape engine to draw custom shapes with highly fluid motion. Instead of traditional basic rounded rectangles, M3 introduces 35 unique shape templates (such as flower, sunny, burst, cookie, etc.) which can morph organically when interacted with.

Introduction

At the core of the MD3 Expressive shape engine is a polygon mathematics library designed to draw and animate custom smooth-cornered paths. They are provided as React components:

  • ShapeMedia: Clip any visual element (image, video, gradient container) into an M3 shape and animates its shape on interaction (e.g. hover).
  • ShapeSvg: Renders a shape directly as a scale-independent inline SVG path, great for micro-animations and vector illustrations.
  • useShapeMorph: A custom hook offering the raw animated CSS clipPath value and event handlers for deeper custom components.

The system ships with 35 predefined shapes based on Android Material 3 Design specifications. You can preview them all below. Hover over any shape to see it morph smoothly into its natural family companion or into a clean circle.

Loading demo...

Sequence Morphing

Use useShapeSequenceMorph to cycle continuously or on-demand across an entire array of shapes (e.g., Organic petals, starbursts, or polygonal containers).

Loading demo...

Content Wrapping

Use <ShapeMedia> to wrap any UI child (gradients, pictures, dashboards). It uses CSS clip-path internally to clip the content safely and efficiently without clipping overflow tools or adding heavy DOM wrappers.

Loading demo...

Morph Playground

Pick any start shape and target shape, then slide the morph progress to see the smooth interpolation calculated in real-time by the pure TypeScript math physics engine.

Loading demo...

SVG Rendering

When you need vector graphics, use <ShapeSvg>. It draws high-fidelity, responsive vector shapes that can be filled, stroked, scaled, and morphed dynamically in real-time.

Loading demo...

Usage

ShapeMedia (Content Clipping)

import { ShapeMedia } from "@bug-on/m3-expressive/shapes";

{/* Wrap image with custom easing configuration */}

<ShapeMedia
  shape="flower"
  morphTo="circle"
  morphOn="hover"
  morphOptions={{ duration: 0.4, easing: "ease-out" }}
  width={160}
  height={160}
>
  <img 
    src="/avatar.jpg" 
    alt="Profile avatar" 
    className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105" 
  />
</ShapeMedia>

{/* Smooth looping auto-play video wrapper */}
<ShapeMedia
  shape="sunny"
  morphTo="circle"
  morphOn="hover"
  width={200}
  height={200}
>
  <video
    src="/nature-stream.mp4"
    autoPlay
    loop
    muted
    playsInline
    className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
  />
</ShapeMedia>

ShapeSvg (SVG Vector rendering)

import { ShapeSvg } from "@bug-on/m3-expressive/shapes";

<ShapeSvg
  shape="sunny"
  width={80}
  height={80}
  fill="#006A60"
/>

useShapeMorph (Custom Canvas/Clip-Path Hook)

import { useShapeMorph } from "@bug-on/m3-expressive/shapes";

function CustomComponent() {
  const { clipPath, handlers } = useShapeMorph({
    shape: "clover4Leaf",
    morphTo: "circle",
    morphOn: "hover",
    morphOptions: { duration: 0.4, easing: [0.34, 1.56, 0.64, 1] }, // Springy easing configuration
    width: 100,
    height: 100,
  });

  return (
    <div
      style={{ clipPath }}
      {...handlers}
      className="w-24 h-24 bg-m3-primary"
    />
  );
}

Best Practices & Accessibility

Do

  • Media Display Optimization: Always apply w-full h-full object-cover CSS classes to child <img> or <video> elements to ensure content fits the polygon clip-path cleanly without distortion.
  • Standard Video Setup: Ensure <video> elements wrapped inside ShapeMedia include autoPlay loop muted playsInline attributes for smooth autoplay across devices.
  • Accessibility Optimization: Provide clear visual descriptions via aria-label and declare role="img" for <ShapeMedia> when displaying informative images or videos.
  • Accurate Corner Rounding: Specify exact width and height dimensions on the component for precise clip-path coordinate calculations.

Don't

  • Avoid Distortion: Avoid unconstrained images or videos without object-cover.
  • No Transition Conflicts: Do not apply CSS transition directly to the clip-path property of parent wrappers to prevent physical animation conflicts with Framer Motion's smooth morphing engine.
  • Limit Complex Shapes at Small Sizes: Avoid overly intricate shapes (e.g., 12-clover) for very small elements (below 24dp) as corner details become blurred.

API Reference

ShapeMedia

PropTypeDefaultDescription
shapeMD3ShapeName | RoundedPolygon—The resting shape.
morphToMD3ShapeName | RoundedPolygon | "auto"—The target shape to morph into. Use "auto" to morph into the recommended family companion.
morphOn"hover" | "click" | "focus" | "scroll" | "none""hover"The trigger condition that starts the shape morphing.
morphOptionsShapeMorphOptions—Optional custom transition properties: duration (seconds) and easing (CSS easing or custom cubic-bezier array).
widthnumber—Component width in pixels. Required for clipPath math calculations.
heightnumber—Component height in pixels. Required for clipPath math calculations.

ShapeSvg

PropTypeDefaultDescription
shapeMD3ShapeName | RoundedPolygon—The SVG shape to render.
morphToMD3ShapeName | RoundedPolygon | "auto"—The target shape to morph into.
progressnumber0Manual interpolation progress between shape and morphTo [0, 1].
widthnumber100Width of the SVG box.
heightnumber100Height of the SVG box.
fillstring"currentColor"Fill color of the SVG path.

useShapeMorph

OptionTypeDefaultDescription
shapeMD3ShapeName | RoundedPolygon—The resting shape (supports smooth transitions when dynamically updated).
morphToMD3ShapeName | RoundedPolygon | "auto"—The target shape to morph into.
morphOn"hover" | "click" | "focus" | "scroll" | "none""hover"The trigger condition that starts the morphing.
morphOptionsShapeMorphOptions—Custom transition properties: duration (seconds) and easing (CSS easing or custom cubic-bezier array).
widthnumber—Component width in pixels.
heightnumber—Component height in pixels.

useShapeSequenceMorph

OptionTypeDefaultDescription
shapesShapeRef[]—Array of shapes to morph through sequentially.
durationnumber0.6Transition duration per morph in seconds.
intervalnumber2.0Interval between transitions in seconds when autoplaying.
autoplaybooleanfalseWhether to automatically cycle through shapes.
loopbooleantrueWhether to loop back to the first shape after reaching the end.
widthnumber—Component width in pixels.
heightnumber—Component height in pixels.