Skip to Content
Mix 2.0 is in development! You can access the Mix 1.0 docs here.
DocsTutorialsCreating Context Variants

Creating a Custom Context Variant

Context variants allow you to apply styles conditionally based on runtime conditions from the BuildContext. This is useful for responding to theme changes, media queries, inherited widgets, or any other context-dependent state.

Understanding Context Variants

A ContextVariant evaluates a condition at build time using the current BuildContext. When the condition is met, the variant’s styles are applied to the widget.

Creating a Basic Context Variant

Let’s create a context variant that responds to a custom InheritedWidget:

class CustomInheritedWidget extends InheritedWidget { final bool flag; const CustomInheritedWidget({ super.key, required this.flag, required super.child, }); static CustomInheritedWidget? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<CustomInheritedWidget>(); } @override bool updateShouldNotify(covariant CustomInheritedWidget oldWidget) { return flag != oldWidget.flag; } }

Now you can create a ContextVariant that checks this inherited widget’s state:

BoxStyler() .color(Colors.red) .size(100, 100) .variant( ContextVariant('custom_flag', (context) { final flag = CustomInheritedWidget.of(context)?.flag ?? false; return flag; }), BoxStyler().color(Colors.blue), );

In this example:

  • The box is normally red with 100x100 size
  • When CustomInheritedWidget.flag is true, the box becomes blue
  • The ContextVariant constructor takes a name and a function that evaluates the condition

Creating Reusable Variant Extensions

For better reusability and a cleaner API, you can create extension methods on WidgetStateVariantMixin:

extension WidgetStateVariantMixinX<T extends Style<S>, S extends Spec<S>> on WidgetStateVariantMixin<T, S> { T onCustomFlag(T style) { return variant( ContextVariant('custom_flag', (context) { final flag = CustomInheritedWidget.of(context)?.flag ?? false; return flag; }), style, ); } }

Now you can use the extension method for a more readable API:

BoxStyler() .color(Colors.red) .size(100, 100) .onCustomFlag( BoxStyler().color(Colors.blue), );

Complete Example

Here’s a full working example:

import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; class CustomInheritedWidget extends InheritedWidget { final bool flag; const CustomInheritedWidget({ super.key, required this.flag, required super.child, }); static CustomInheritedWidget? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<CustomInheritedWidget>(); } @override bool updateShouldNotify(covariant CustomInheritedWidget oldWidget) { return flag != oldWidget.flag; } } class Example extends StatelessWidget { const Example({super.key}); BoxStyler get box => BoxStyler() .color(Colors.red) .size(100, 100) .variant( ContextVariant('custom_flag', (context) { final flag = CustomInheritedWidget.of(context)?.flag ?? false; return flag; }), BoxStyler().color(Colors.blue), ); @override Widget build(BuildContext context) { return CustomInheritedWidget(flag: true, child: box()); } }