Skip to Content
Mix 2.0 is in development! You can access the Mix 1.0 docs here.
DocsGuidesWidget Modifiers

Widget Modifiers

Modifiers wrap a widget with another widget (like Transform, Padding, or Opacity) to add effects without changing the widget tree. Use the .wrap() method with a ModifierMix class.

How Modifiers Work

Use .wrap() with a modifier mix class to wrap a widget:

import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; final style = BoxStyler() .color(Colors.red) .size(100, 100) .wrap(.opacity(0.4));

This produces a widget tree equivalent to Opacity(opacity: 0.4, child: Container(...)).

Built-in Modifiers

ModifierMix ClassDescriptionWrapper Widget
.opacity(value)Sets opacityOpacity
.padding(insets)Adds paddingPadding
.align(alignment)Sets alignmentAlign
.aspectRatio(ratio)Constrains aspect ratioAspectRatio
.flexible(flex: flex, fit: fit)Makes flexible in Flex layoutsFlexible
.transform(matrix)Applies transformTransform
.visibility(visible: visible)Shows/hides widgetVisibility
.clipRect()Clips to rectangleClipRect
.clipRRect(borderRadius: radius)Clips to rounded rectangleClipRRect
.clipOval()Clips to ovalClipOval

Usage Examples

import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; // Combine multiple modifiers final cardStyle = BoxStyler() .color(Colors.white) .size(200, 100) .wrap(.opacity(0.9)) .wrap(.padding(.all(16))) .wrap(.align(alignment: .center)); // Use transform methods for scale/rotate final buttonStyle = BoxStyler() .color(Colors.blue) .paddingAll(16) .scale(1.0) .onHovered(BoxStyler().scale(1.1));

Modifier Ordering

Modifiers are applied from innermost to outermost in the order they are chained. This means the last modifier in the chain becomes the outermost wrapper:

// Result: Align → Opacity → Padding → Box final style = BoxStyler() .wrap(.padding(.all(8))) // innermost wrapper .wrap(.opacity(0.5)) // middle wrapper .wrap(.align(alignment: .center)); // outermost wrapper

The order of modifiers matters. Padding applied before opacity will have its padding inside the opacity effect, while padding after opacity will be outside.

Creating Custom Modifiers

Create custom modifiers with two classes:

  1. WidgetModifier - Builds the wrapper widget
  2. ModifierMix - Handles merging and resolving

Step 1: Create the WidgetModifier

import 'package:flutter/widgets.dart'; import 'package:mix/mix.dart'; /// Modifier that applies opacity to its child. final class OpacityModifier extends WidgetModifier<OpacityModifier> { /// Opacity value between 0.0 and 1.0 (inclusive). final double opacity; const OpacityModifier([double? opacity]) : opacity = opacity ?? 1.0; @override OpacityModifier copyWith({double? opacity}) { return OpacityModifier(opacity ?? this.opacity); } @override OpacityModifier lerp(OpacityModifier? other, double t) { if (other == null) return this; // Linear interpolation for smooth animations return OpacityModifier(MixOps.lerp(opacity, other.opacity, t)!); } @override List<Object?> get props => [opacity]; @override Widget build(Widget child) { return Opacity(opacity: opacity, child: child); } }

Key methods to implement:

MethodPurpose
copyWithCreates a copy with optional property updates
lerpLinear interpolation for animations between two modifier states
propsList of properties for equality comparison
buildConstructs the wrapper widget

Step 2: Create the ModifierMix

The ModifierMix class makes the modifier mergeable and resolvable. It uses Prop<T> for properties to support tokens and lazy resolution.

import 'package:flutter/widgets.dart'; import 'package:mix/mix.dart'; /// Mix class for applying opacity modifications. class OpacityModifierMix extends ModifierMix<OpacityModifier> { final Prop<double>? opacity; const OpacityModifierMix.create({this.opacity}); /// Convenience constructor with direct value OpacityModifierMix({double? opacity}) : this.create(opacity: Prop.maybe(opacity)); @override OpacityModifier resolve(BuildContext context) { return OpacityModifier(opacity?.resolveProp(context)); } @override OpacityModifierMix merge(OpacityModifierMix? other) { if (other == null) return this; return OpacityModifierMix.create( opacity: MixOps.merge(opacity, other.opacity), ); } @override List<Object?> get props => [opacity]; }

Key methods:

MethodPurpose
resolveResolves Prop values using BuildContext and creates the final WidgetModifier
mergeCombines two ModifierMix instances, with other’s values taking precedence
propsList of properties for equality comparison

Step 3: Use the Custom Modifier

To use your custom modifier in a style, use the .wrap() method:

import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; final style = BoxStyler() .color(Colors.red) .size(100, 100) .wrap(.opacity(0.4)); // With tokens final $opacityToken = DoubleToken('custom.opacity'); final tokenStyle = BoxStyler() .color(Colors.blue) .wrap(.opacity(Prop.token($opacityToken)));

Best Practices

  • Use modifiers for transforms, visibility, layout adjustments, and clipping
  • Use styler methods (not modifiers) for colors, borders, shadows
  • Avoid deeply nested modifier chains
  • Implement lerp properly for smooth animations