Mix Lint helps you enforce coding standards and best practices in Flutter apps using Mix.
Add mix_lint as a dev dependency:
dart pub add -d mix_lintEnable the plugin in analysis_options.yaml (requires Dart ≥ 3.10 / Flutter ≥ 3.38):
plugins:
mix_lint: anyEnable individual lint rules:
plugins:
mix_lint:
diagnostics:
mix_avoid_defining_tokens_within_style: true
mix_avoid_defining_tokens_within_scope: true
mix_avoid_token_ref_outside_mix: true
mix_avoid_empty_variants: true
mix_max_number_of_attributes_per_style: true
mix_variants_last: true
mix_mixable_styler_has_create: true
mix_prefer_dot_shorthands: trueThen restart the analysis server (or your IDE) to pick up the new plugin.
Use standard // ignore: comments with the format mix_lint/<rule_name>:
// ignore: mix_lint/mix_variants_last
final style = BoxStyler().onHovered(x).paddingAll(16);Ensure that MixToken instances are not created directly inside Styler method calls. Define tokens outside the style (e.g. top-level or as local constants), then pass them in.
Tokens are meant to be shared across the app. Creating them inline inside a Styler makes them local to that call and harder to reuse or reference elsewhere.
// Inline token inside a Styler
final style = BoxStyler()
.color(ColorToken('primary').call())
.borderRadiusTopLeft(RadiusToken('rounded')());final primary = ColorToken('primary');
final rounded = RadiusToken('rounded');
final style = BoxStyler()
.color(primary())
.borderRadiusTopLeft(rounded());Ensure that MixToken instances are not created directly inside MixScope constructors. Define tokens outside (e.g. top-level or as local constants), then use them as keys in the scope's maps.
The scope maps tokens to resolved values; the tokens themselves should already exist. Creating them inline makes them unreferenceable elsewhere and can lead to duplication.
MixScope(
colors: {
ColorToken('primary'): Colors.blue,
},
child: child,
);final primary = ColorToken('primary');
MixScope(
colors: {
primary: Colors.blue,
},
child: child,
);Ensure that a MixToken reference is only passed to Mix styling APIs.
Calling a token — token() (or token.mix() on the tokens that expose it) — does not return a concrete value. It returns a reference sentinel (e.g. ColorRef, RadiusRef) that only resolves later inside Mix's pipeline, against the surrounding MixScope. Pass that sentinel to a non-Mix API — a plain Flutter widget, a dart:core function — and it never resolves, producing a silent bug.
The rule allows the reference when it is an argument to anything whose receiver/constructed type descends from Mix (all Stylers and *Mix value utilities, whether shipped in Mix or generated in your package via @MixableType/@MixableSpec); it flags the reference when the consuming API is provably not Mix. To read a concrete value outside Mix, use token.resolve(context) instead.
This is a warning rather than a hint: a misrouted reference is a correctness bug, not a style preference.
Note: the check is syntactic. A reference first stored in a variable (
final c = token(); Container(color: c);) is not detected.
final primary = ColorToken('primary');
// Reference escapes into a non-Mix API and never resolves.
Container(color: primary());final primary = ColorToken('primary');
// Pass the reference to a Mix styling API…
Box(style: BoxStyler().color(primary()));
// …or resolve it to a concrete value for non-Mix APIs.
Container(color: primary.resolve(context));Don't create a Styler that only has .on variant methods (e.g. .onHovered, .onDark, .onPressed). Always include base styling so the style has a default appearance; then add variants for overrides.
// Styler with only variant methods, no base style
final style = BoxStyler()
.onHovered(BoxStyler().color(Colors.blue))
.onPressed(BoxStyler().color(Colors.green));final style = BoxStyler()
.color(Colors.grey)
.onHovered(BoxStyler().color(Colors.blue))
.onPressed(BoxStyler().color(Colors.green));Limit the number of attributes per style. The default value is 15. This rule encourages keeping styles concise and focused; split large styles into smaller, reusable Stylers and compose with merge().
The rule reports when a Styler constructor or a variant-style invocation has more than max_number arguments.
// One large style with too many arguments (exceeds max_number)
final style = BoxStyler()
.color(Colors.blue)
.paddingAll(8)
.margin(.all(4))
.alignment(.center)
.borderRounded(8)
.width(200)
.height(100)
.opacity(0.9)
.onHovered(BoxStyler()
.color(Colors.red)
.paddingAll(12)
.margin(.all(6))
.borderRounded(10)
.width(220)
.height(120)
.opacity(1.0));final layout = BoxStyler()
.paddingAll(8)
.margin(.all(4))
.alignment(.center);
final appearance = BoxStyler()
.color(Colors.blue)
.borderRounded(8)
.width(200)
.height(100)
.opacity(0.9);
final hovered = BoxStyler()
.color(Colors.red)
.paddingAll(12)
.margin(.all(6))
.borderRounded(10)
.width(220)
.height(120)
.opacity(1.0);
final style = layout
.merge(appearance)
.onHovered(hovered);The maximum number of attributes allowed per style (or per variant invocation). The default value is 15.
Ensures that variant methods (onHovered, onPressed, onFocused, onDisabled, onDark, etc.) are placed at the bottom of the Styler chain, after all base styling methods. Mixing variant calls between base properties makes the style harder to read and reason about.
final style = BoxStyler()
.color(Colors.red)
.onHovered(.color(Colors.blue))
.paddingAll(16)
.borderRounded(8)
.onPressed(.color(Colors.green));final style = BoxStyler()
.color(Colors.red)
.paddingAll(16)
.borderRounded(8)
.onHovered(.color(Colors.blue))
.onPressed(.color(Colors.green));Prefer Dart's dot shorthand syntax when calling static methods or constructors on types that can be inferred from context. Instead of writing the full type name (e.g. EdgeInsetsGeometryMix.all(10) or TextStyler.color(...)), use the leading dot (e.g. .all(10) or .color(...)). This keeps code concise and readable while remaining type-safe. Requires Dart 3.11 or later.
final style = BoxStyler()
.padding(EdgeInsetsGeometryMix.all(10))final style = BoxStyler()
.padding(.all(10))Ensures that every class annotated with @MixableStyler defines a named constructor .create. The generated Styler mixin and the rest of the Mix API expect this constructor for const instantiation, merging, and default styles (e.g. const BoxStyler.create()).
@MixableStyler()
class MyStyler extends Style<MySpec> with _$MyStylerMixin {
final Prop<Color>? $color;
MyStyler({Prop<Color>? color}) : $color = color;
}@MixableStyler()
class MyStyler extends Style<MySpec> with _$MyStylerMixin {
final Prop<Color>? $color;
const MyStyler.create({
Prop<Color>? color,
super.variants,
super.modifier,
super.animation,
}) : $color = color;
MyStyler({Color? color, ...}) : this.create(color: Prop.maybe(color), ...);
}