mix 2.0.0
mix: ^2.0.0 copied to clipboard
An expressive way to effortlessly build design systems in Flutter.
Mix is a styling system for Flutter that separates style definitions from widget structure. It provides a composable, type-safe way to define and apply styles using a fluent API, design tokens, and context-aware variants.
- Compose, merge, and apply styles across widgets
- Write maintainable styling definitions separate from widget code
- Adapt styles conditionally based on interactions and context
Why Mix? #
Flutter's built-in styling works well for simple widgets, but as your app grows, common pain points emerge:
- Style duplication: The same colors, spacing, and borders are repeated across widgets with no easy way to share them.
- Tight coupling: Style logic lives inside
build()methods, making it hard to reuse or test independently. - No conditional styling: Adapting styles for hover, press, dark mode, or breakpoints requires manual boilerplate.
Mix solves these by giving you a dedicated styling layer that stays consistent across widgets and files — without being tied to Material Design.
Goals #
- Define styles outside widgets while retaining
BuildContextaccess (resolved at build time, likeTheme.of, with more flexibility) - Reuse style definitions across your app for consistency
- Adapt styles conditionally using variants (hover, dark mode, breakpoints)
- Type-safe composability using Dart's type system
Guiding Principles #
- Simple — Thin layer over Flutter; widgets remain compatible and predictable
- Consistent — API mirrors Flutter naming conventions
- Composable — Build complex styles from simple, reusable pieces
- Extensible — Override and extend utilities to fit your needs
Getting Started #
Prerequisites #
- Dart SDK: 3.11.0 or higher
- Flutter: 3.41.0 or higher
Installation #
flutter pub add mix
Or in pubspec.yaml:
dependencies:
mix: <latest>
import 'package:mix/mix.dart';
First Widget #
final cardStyle = BoxStyler()
.size(240, 100)
.color(Colors.blue)
.alignment(.center)
.borderRounded(12)
.border(.all(.color(Colors.black).width(1).style(.solid)));
Box(
style: cardStyle,
child: StyledText(
'Hello Mix',
style: TextStyler().color(Colors.white).fontSize(18),
),
);
Understanding the Styler Pattern #
Fluent API: BoxStyler() #
The default constructor gives you a chainable API:
final style = BoxStyler()
.color(Colors.blue)
.paddingAll(16)
.borderRounded(8);
Use this when defining styles with direct values and chaining properties.
Prop-Based API: BoxStyler.create() #
The .create() constructor accepts Prop<T> for advanced composition (tokens, directives):
final style = BoxStyler.create(
color: Prop.token($primaryColor),
padding: Prop.value(EdgeInsets.all(16)),
);
Use this when working with design tokens or number directives like multiply() or clamp().
Key Features #
Styling API #
Define styles with a fluent, chainable API. Style composition and override are supported — later attributes override earlier ones when chained:
import 'package:flutter/material.dart';
import 'package:mix/mix.dart';
final boxStyle = BoxStyler()
.height(100)
.width(100)
.color(Colors.purple)
.borderRounded(10);
final textStyle = TextStyler()
.fontSize(20)
.fontWeight(.bold)
.color(Colors.black);
// Compose from a base style
final base = BoxStyler()
.paddingX(16)
.paddingY(8)
.borderRounded(8)
.color(Colors.black);
final solid = base.color(Colors.blue);
Dynamic Styling (Variants) #
Styles adapt to interactions and context (hover, press, dark mode, breakpoints) in one place:
final buttonStyle = BoxStyler()
.height(50)
.borderRounded(25)
.color(Colors.blue)
.onHovered(.color(Colors.blue.shade700))
.onDark(.color(Colors.blue.shade200));
Built-in variants include onHovered, onPressed, onFocused, onDisabled, onDark, onLight, onBreakpoint, onMobile, onTablet, onDesktop, and platform/context variants.
Design Tokens and Theming #
Define reusable tokens and provide them via MixScope:
final $primary = ColorToken('primary');
final $spacingMd = SpaceToken('spacing.md');
MixScope(
colors: { $primary: Colors.blue },
spaces: { $spacingMd: 16.0 },
child: MyApp(),
);
final style = BoxStyler()
.color($primary())
.paddingAll($spacingMd());
Animations #
- Implicit — Values animate smoothly with
.animate(AnimationConfig....) - Phase — Multi-step flows (e.g. tap → compress → expand) with
.phaseAnimation(...) - Keyframe — Full control with tracks and keyframes
Widget Modifiers #
Some visual effects — opacity, clipping, visibility — aren't style properties. Modifiers let you declare widget wrappers inside your style so they stay composable and animatable.
Directives #
Directives transform values (text casing, number scaling, color adjustments) at resolve time, keeping transformations inside the style so they survive merging.
Utility-First Approach #
Stylers expose small, composable utilities you combine. The API follows Flutter naming so it stays familiar:
BoxStyler()
.paddingAll(20)
.paddingX(16)
.paddingY(8)
.borderAll(color: Colors.red);
Ecosystem #
| Package | Description |
|---|---|
| mix_annotations | Annotations for code generation |
| mix_generator | build_runner generator for specs |
| mix_lint | Custom linter rules |
| mix_tailwinds | Utility-first styling inspired by Tailwind CSS |
Documentation #
- Introduction
- Getting started
- Styling
- Dynamic styling
- Design tokens
- Animations
- Widget modifiers
- Directives
- Widgets (Box, Text, Icon, FlexBox, Stack, etc.)
