Material Expressive
A complete Material 3 Expressive design system for Flutter.
This is not a widget library. It's a design system that enhances Flutter's existing Material widgets through tokens, spring physics, 35 morphable shapes, vibrant colors, emphasized typography, and expressive component behaviors.
Inspired by Google's M3 Expressive redesign announced at I/O 2025.
Installation
dependencies:
material_expressive: ^0.8.0
import 'package:material_expressive/material_expressive.dart';
Getting Started
1. Generate a theme
final theme = ExpressiveTheme.fromSeed(
seedColor: Colors.deepOrange,
shapeType: ExpressiveShapeType.organic,
);
2. Apply to your app
MaterialApp(
theme: ExpressiveComponentThemes.applyExpressive(theme.materialTheme),
darkTheme: ExpressiveComponentThemes.applyExpressive(theme.materialDarkTheme),
builder: (context, child) => ExpressiveThemeProvider(
themeData: theme,
child: child!,
),
);
3. Access tokens anywhere
context.tokens.spacing.lg // adaptive spacing
context.tokens.colors.primary // semantic color
context.tokens.radius.md // corner radius
context.tokens.shape.lg // ShapeBorder
context.adaptiveSpacing.xl // auto phone/tablet/desktop
Sub-libraries
Import only what you need:
| Import | Contents |
|---|---|
material_expressive.dart |
Everything |
tokens.dart |
Design tokens (colors, spacing, radius, elevation, motion, typography) |
shapes.dart |
35 MaterialShapes + morphing + RTL |
motion.dart |
Spring physics, MotionScheme, transitions, gesture spring, accessibility |
theme.dart |
Theme generation, vibrant colors, color harmonization |
components.dart |
Surfaces, icons, buttons, carousel, dialog, sheet, snackbar, search |
templates.dart |
Ready-made screen templates |
core.dart |
Context extensions, adaptive utilities, layout helpers |
devtools.dart |
Spacing overlay, token inspector |
Shapes (35 total)
All official M3 Expressive shapes, each defined as interpolatable points:
// Use as static decoration
Container(
decoration: ShapeDecoration(
shape: MorphableShapeBorder(points: MaterialShapes.heart),
color: Colors.pink,
),
)
// Animate between shapes
ShapeMorph(
shape: MaterialShapes.flower, // change this → smooth morph
size: 80,
color: scheme.primary,
duration: Duration(milliseconds: 500),
)
// RTL-aware
RtlShapes.directional(context, MaterialShapes.arrow)
All shapes: circle, square, pill, diamond, triangle, pentagon, arch, arrow, heart, flower, clover4Leaf, clover8Leaf, cookie4/6/7/9/12Sided, boom, softBoom, burst, softBurst, sunny, verySunny, fan, gem, ghostish, bun, oval, puffy, puffyDiamond, semiCircle, slanted, pixelCircle, pixelTriangle, clamShell.
Spring Physics (MotionScheme)
Two predefined schemes matching M3 Expressive motion tokens:
// Standard — subtle, functional transitions
MotionScheme.standard.defaultSpatial
MotionScheme.standard.fastEffects
// Expressive — bouncy, engaging hero interactions
MotionScheme.expressive.defaultSpatial // stiffness: 380, damping: 0.73
MotionScheme.expressive.fastSpatial
// Use on any AnimationController
controller.animateWithSpring(
MotionScheme.expressive.defaultSpatial,
target: 1.0,
);
// Per-component assignments
ComponentMotion.hero // expressive scheme
ComponentMotion.navigation // standard scheme
ComponentMotion.dialog // expressive.fastSpatial
ComponentMotion.button // standard.fastSpatial
SpringTransition widget
SpringTransition(
isActive: _expanded,
spring: MotionScheme.expressive.defaultSpatial,
scaleActive: 1.3,
scaleInactive: 1.0,
child: myWidget,
)
Gesture-driven spring
GestureSpringBox(
spring: MotionScheme.expressive.defaultSpatial,
axis: Axis.vertical,
maxOffset: 100,
snapBack: true,
child: Card(...),
)
Accessibility
// Respects system "reduce motion" setting
final spring = MotionAccessibility.adaptiveSpring(
context, MotionScheme.expressive.defaultSpatial);
final dur = MotionAccessibility.adaptiveDuration(
context, Duration(milliseconds: 400));
Vibrant Colors
M3 Expressive uses more saturated palettes than standard Material You:
// Vibrant scheme (boosted saturation)
final scheme = VibrantColorScheme.fromSeed(
seedColor: Colors.blue,
saturationBoost: 0.2,
);
// Harmonize brand colors with your theme
final brandRed = ColorHarmonization.harmonize(
myBrandRed, seedColor, amount: 0.25);
// Generate all semantic colors at once
final semantic = ColorHarmonization.harmonizeAll(
seed: seedColor,
success: Colors.green,
warning: Colors.orange,
info: Colors.blue,
error: Colors.red,
);
Expressive Typography
// Apply emphasis (bolder, larger headlines)
final textTheme = ExpressiveTypography.emphasized(
base.textTheme,
emphasisLevel: 0.6, // 0.0 = standard, 1.0 = max
);
// Variable font axes (if font supports it)
Text('Hello', style: ExpressiveTypography.withVariableAxes(
baseStyle,
weight: 700,
opticalSize: 48,
));
Components
Button Group
ExpressiveButtonGroup(
buttons: [
ExpressiveButtonGroupItem(label: 'Day', icon: Icons.today),
ExpressiveButtonGroupItem(label: 'Week'),
ExpressiveButtonGroupItem(label: 'Month'),
],
selectedIndex: _selected,
onSelected: (i) => setState(() => _selected = i),
)
Split Button
ExpressiveSplitButton(
label: 'Save',
icon: Icons.save,
onPressed: _save,
onDropdown: _showOptions,
)
Floating Toolbar
ExpressiveFloatingToolbar(items: [
FloatingToolbarItem(icon: Icons.format_bold, isSelected: true, onPressed: () {}),
FloatingToolbarItem(icon: Icons.format_italic, onPressed: () {}),
const FloatingToolbarItem.divider(),
FloatingToolbarItem(icon: Icons.link, onPressed: () {}),
])
Carousel
ExpressiveCarousel(
height: 200,
viewportFraction: 0.85,
items: [Card(...), Card(...), Card(...)],
)
Search Bar (morph expand)
ExpressiveSearchBar(
controller: _searchCtrl,
hintText: 'Search...',
onChanged: (q) {},
)
Bottom Sheet
showExpressiveBottomSheet(
context: context,
snap: true,
snapSizes: [0.25, 0.5, 0.9],
builder: (_) => MyContent(),
);
Dialog
showExpressiveDialog(
context: context,
builder: (_) => ExpressiveAlertDialog(
icon: Icon(Icons.warning),
title: Text('Discard changes?'),
content: Text('Your edits will be lost.'),
actions: [
TextButton(onPressed: () {}, child: Text('Cancel')),
FilledButton(onPressed: () {}, child: Text('Discard')),
],
),
);
Snackbar
showExpressiveSnackBar(context,
message: 'File saved',
icon: Icons.check_circle,
actionLabel: 'Undo',
onAction: _undo,
);
State Morph Container
StateMorphContainer(
isActive: _selected,
activeShape: MaterialShapes.circle,
inactiveShape: MaterialShapes.square,
spring: MotionScheme.expressive.defaultSpatial,
child: Icon(Icons.star),
)
Shape Container Transform
ShapeContainerTransform(
closedShape: MaterialShapes.circle,
closedSize: 56,
closedBuilder: (ctx, open) => IconButton(icon: Icon(Icons.add), onPressed: open),
openBuilder: (ctx, close) => DetailScreen(onBack: close),
)
Loading Indicators
ContainedLoadingIndicator(segments: 4) // M3 Expressive segmented arc
WavyLinearProgressIndicator(value: 0.6) // wavy determinate linear
WavyLinearProgressIndicator() // wavy indeterminate linear
WavyCircularProgressIndicator(value: 0.4) // wavy determinate circular
WavyCircularProgressIndicator() // wavy indeterminate circular
OrganicLoadingIndicator() // blob animation
PulsingDotsIndicator() // pulsing dots
MorphingShapeIndicator() // morphing shape
Surfaces
ExpressiveSurface(
type: ExpressiveSurfaceType.primaryTinted,
padding: EdgeInsets.all(16),
child: Text('Tinted surface'),
)
Types: surface, containerLow, container, containerHigh, primaryTinted, secondaryTinted, tertiaryTinted.
Expressive Icons
Standard Icons.* work as-is. This adds the M3 Expressive presentation — shaped containers, sizing, optical adjustments:
// Icon in a shaped container
ExpressiveIcon(Icons.favorite,
size: ExpressiveIconSize.large,
shapeType: ExpressiveShapeType.organic,
containerColor: scheme.primaryContainer,
iconColor: scheme.onPrimaryContainer,
)
// Small contained icon with tap
ExpressiveIcon(Icons.add,
size: ExpressiveIconSize.small,
filled: true,
onPressed: () {},
)
// Apply expressive icon theme globally
IconTheme(
data: ExpressiveIconTheme.expressive(scheme: scheme),
child: ...,
)
Tip: For the latest Material Symbols variable font icons, pair this package with material_symbols_icons. Our
ExpressiveIconThemesetsopticalSize,weight,grade, andfillwhich variable icon fonts respond to.
Templates
Ready-made screens: LoginTemplate, ProfileTemplate, DashboardTemplate, ChatTemplate, SettingsTemplate, SearchTemplate, ListTemplate, MediaTemplate, ProductDetailTemplate.
Theme Extensions
Apply expressive styling to all standard Material widgets at once:
final expressiveTheme = ExpressiveComponentThemes.applyExpressive(
theme.materialTheme,
coloredAppBar: true,
);
Or apply individually:
expressiveFab(scheme:)— organic-shaped FABexpressiveNavBar(scheme:)— taller nav with bold labelsexpressiveAppBar(scheme:, colored:)— bolder titleexpressiveIconButton(scheme:)— larger touch targetsexpressiveCarouselCard(scheme:)— shaped carousel cards
Dev Tools
// Spacing grid overlay
SpacingOverlay(enabled: kDebugMode, child: MyApp())
// Token inspector drawer
Scaffold(endDrawer: TokenInspector())
License
MIT
Libraries
- components
- Components: surfaces, state layers, loading indicators, animated icons, button groups, split buttons, floating toolbar, carousel, dialogs, bottom sheets, snackbars, search bar, expressive icons, wavy progress, and theme extensions.
- core
- Core utilities: context extensions, adaptive helpers, layout primitives.
- devtools
- Debugging tools: spacing overlay, token inspector.
- material_expressive
- Material Expressive — A complete expressive design system for Flutter.
- motion
- Motion system: spring physics, motion schemes, transitions, page routes, gesture-driven animation, shape transforms, and accessibility.
- shapes
- Material 3 Expressive shape system — 35 shapes, morphing, RTL support.
- theme
- Theme generation, vibrant colors, color harmonization, image extraction, and token provider.
- tokens
- Design tokens: colors, typography, spacing, radius, elevation, motion, shapes.