m3_expressive 1.0.0 copy "m3_expressive: ^1.0.0" to clipboard
m3_expressive: ^1.0.0 copied to clipboard

Material 3 Expressive components for Flutter. Morphing shapes, animated indicators, swipe-to-dismiss list items, and container transforms faithful to the Android 16 design spec.

m3_expressive #

Material 3 Expressive components for Flutter.

Google's Android 16 design language introduces a new generation of motion and shape work that Flutter's built-in widgets do not yet cover. This package fills that gap with five production-ready components that follow the M3 Expressive spec as closely as possible.

https://github.com/user-attachments/assets/c6f8a013-7280-4289-93a3-8429ee3e31b1

https://github.com/user-attachments/assets/0de34bf5-52b1-4c34-a87b-d2e29ee32c99

https://github.com/user-attachments/assets/f3274caa-fda7-48ff-814a-ad02a20396a1

https://github.com/user-attachments/assets/4dd2a67e-359a-4551-a4e1-b03724563b83

https://github.com/user-attachments/assets/b3e36f01-9606-4535-bcb7-540a6bd0fb52


Installation #

dependencies:
  m3_expressive: ^1.0.0
flutter pub get

Then import once in any file that needs it:

import 'package:m3_expressive/m3_expressive.dart';

Components #

M3LoadingIndicator #

A morphing square that cycles through four corner-radius configurations while rotating. Drop-in replacement for CircularProgressIndicator.

// Defaults: size 48, color from Theme.colorScheme.primary
const M3LoadingIndicator()

// Custom
M3LoadingIndicator(
  size: 32,
  color: Colors.teal,
  duration: const Duration(milliseconds: 1000),
)

Parameters

Parameter Type Default Description
size double 48 Width and height of the indicator
color Color? colorScheme.primary Fill color
duration Duration 1400 ms Duration of one full morph cycle

M3RefreshIndicator #

Pull-to-refresh with a circular container that scales in from the top as the user pulls. Inside the circle, a shape morphs continuously through seven M3 Expressive forms using Catmull-Rom interpolation.

// Minimal usage
M3RefreshIndicator(
  onRefresh: _handleRefresh,
  child: ListView(...),
)

// Custom colors
M3RefreshIndicator(
  onRefresh: _handleRefresh,
  backgroundColor: Colors.indigo.shade100,
  shapeColor: Colors.indigo,
  child: ListView(...),
)

Parameters

Parameter Type Default Description
onRefresh Future<void> Function() required Called when refresh is triggered
child Widget required The scrollable content
indicatorSize double 56 Diameter of the indicator circle
triggerDistance double 80 Pull distance required to trigger
backgroundColor Color? colorScheme.primaryContainer Circle background
shapeColor Color? colorScheme.primary Shape fill color
morphDuration Duration 1600 ms Duration of one shape cycle while dragging

The underlying painter is also public as M3ShapeMorphPainter for embedding in your own CustomPaint.


M3DismissibleListItem #

A list card with a morphing swipe-to-dismiss gesture. As the user drags horizontally, the card corners round toward a pill shape and a colored slab emerges from behind. The delete icon springs in past the halfway point. Releasing above the commit threshold (or with a fast fling) dismisses the item. Releasing below it snaps back with an elastic spring.

M3DismissibleListItem(
  onDismissed: () => _deleteItem(item),
  onTap: () => _openItem(item),
  child: MyItemContent(item),
)

// Custom colors and icon
M3DismissibleListItem(
  onDismissed: () => _archiveItem(item),
  onTap: () => _openItem(item),
  deleteColor: Colors.orange,
  deleteIcon: Icons.archive_rounded,
  cardColor: theme.colorScheme.primaryContainer,
  child: MyItemContent(item),
)

Parameters

Parameter Type Default Description
onDismissed VoidCallback required Called when dismiss is committed
onTap VoidCallback required Called on tap
child Widget required Card content
cardColor Color? colorScheme.surfaceContainerHighest Card background
borderColor Color? same as cardColor Card border
deleteColor Color? colorScheme.error Slab background at full reveal
deleteOnColor Color? colorScheme.onError Icon color at full reveal
deleteIcon IconData Symbols.delete_rounded Slab icon
morphThreshold double 72 Pixels to fully morph the radius
commitThreshold double 72 Pixels to commit the dismiss
velocityThreshold double 900 px/s to commit regardless of distance
radiusMin double 18 Corner radius at rest
radiusMax double 40 Corner radius at full morph

M3UndoPill #

A floating pill with a timed progress bar. Appears after a destructive action and counts down until calling onComplete. The user can cancel at any time by tapping the undo button or the dismiss icon.

Intended to be placed inside a Stack above your scrollable content.

Stack(
  children: [
    ListView(...),
    M3UndoPill(
      label: 'Item removed',
      onComplete: () => _permanentlyDelete(item),
      onCancel: () => _restoreItem(item),
    ),
  ],
)

// Custom
M3UndoPill(
  label: 'Message deleted',
  undoLabel: 'Restore',
  duration: const Duration(seconds: 6),
  accentColor: Colors.teal,
  onComplete: _onComplete,
  onCancel: _onCancel,
)

Parameters

Parameter Type Default Description
label String required Text describing the action
onComplete VoidCallback required Called when the timer expires
onCancel VoidCallback required Called when the user cancels
undoLabel String 'Undo' Undo button text
duration Duration 4 seconds Countdown duration
backgroundColor Color? colorScheme.surfaceContainerLow Pill track color
progressColor Color? colorScheme.surfaceContainerHighest Progress bar color
accentColor Color? colorScheme.primary Undo button text color
foregroundColor Color? colorScheme.onSurface Label and icon color
dismissIcon IconData Symbols.close_rounded Dismiss button icon
horizontalPadding double 48 Inset from screen edges

DraggableContainerButton and openContainerTransform #

A Material 3 container transform transition with both tap and drag support.

DraggableContainerButton wraps any widget. On tap it immediately commits the navigation. On upward drag it follows the finger with a live morph preview painted in an Overlay above the navigation bar. Releasing above 40% of the trigger distance (or with a fast enough flick) navigates forward. Releasing below snaps back with a spring.

DraggableContainerButton(
  closedColor: theme.colorScheme.primaryContainer,
  closedRadius: BorderRadius.circular(28),
  pageBuilder: (_) => const DetailPage(),
  onReturn: _refreshData,
  child: MyButton(),
)

openContainerTransform is the programmatic equivalent for cases where you manage the tap gesture yourself.

final _key = GlobalKey();

// On the source widget:
Container(key: _key, child: ...)

// On tap:
await openContainerTransform(
  context: context,
  sourceKey: _key,
  closedColor: theme.colorScheme.primaryContainer,
  closedRadius: BorderRadius.circular(28),
  pageBuilder: (_) => const DetailPage(),
);

DraggableContainerButton parameters

Parameter Type Default Description
closedColor Color required Button color in closed state
closedRadius BorderRadius required Button radii in closed state
pageBuilder WidgetBuilder required Builds the destination page
child Widget required Button content
onReturn VoidCallback? null Called after the user returns
triggerDistance double? 35% screen height Upward drag to reach t=1
onProgressUpdate void Function(double)? null Drag progress in [0, 1]
onTapValidation Future<bool> Function()? null Async guard before tap commit
onDragValidation bool Function()? null Sync guard before drag starts
enableDrag bool true Enable or disable drag gesture
openColor Color? colorScheme.surface Destination page background
scrimColor Color? Colors.black Scrim color

Theming #

All color parameters default to values from the ambient Theme.of(context).colorScheme. An app using standard Material 3 theming requires no color customization at all. Dynamic color, dark mode, and custom color schemes are all handled automatically.


Requirements #

Shape definitions provided by the material_shapes library by Kostiantyn Sokolovskyi, used under the MIT license.

  • Flutter 3.10 or higher
  • Dart 3.0 or higher

License #

MIT. See LICENSE.

4
likes
150
points
16
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Material 3 Expressive components for Flutter. Morphing shapes, animated indicators, swipe-to-dismiss list items, and container transforms faithful to the Android 16 design spec.

Repository (GitHub)
View/report issues
Contributing

License

MIT (license)

Dependencies

flutter, vector_math

More

Packages that depend on m3_expressive