mix 2.2.0-beta.2 copy "mix: ^2.2.0-beta.2" to clipboard
mix: ^2.2.0-beta.2 copied to clipboard

An expressive way to effortlessly build design systems in Flutter.

Mix logo

GitHub stars Pub Version Pub Likes Pub Points MIT Licence Awesome 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 BuildContext access (resolved at build time, like Theme.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(.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);

Styling guide →

Wrapping Layouts #

WrapBox combines Box chrome with Flutter's run-based Wrap layout. Its Wrap fields are available directly on WrapBoxStyler:

final tagCloud = WrapBoxStyler()
    .paddingAll(16)
    .spacing(8)
    .runSpacing(10)
    .wrapAlignment(WrapAlignment.center);

WrapBox(style: tagCloud, children: tags);

On the composite styler, alignment and clipBehavior configure the outer Box; wrapAlignment and wrapClipBehavior configure the inner Wrap. Use .flow(WrapStyler(...)) when direct nested-style composition is needed. See the runnable WrapBox example.

Grid Layouts #

GridBox uses fixed and fractional tracks and can adapt to the width offered by its own parent. Dot shorthand keeps nested track and breakpoint declarations compact:

final GridBoxStyler dashboardGrid = .equalColumns(3)
    .gap(16)
    .autoRows(.fixed(220))
    .onConstraints(
  .maxWidth(720),
  .equalColumns(1).gap(12),
);

GridBox(style: dashboardGrid, children: panels);

onConstraints observes local Grid constraints; onBreakpoint continues to observe the viewport. Compatible track, row, and gap changes can use Mix's implicit animate API. See the Grid layout guide and the runnable Grid examples.

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.

Dynamic styling guide →

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());

Design tokens guide →

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

Animations guide →

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.

Widget modifiers guide →

Directives #

Directives transform values (text casing, number scaling, color adjustments) at resolve time, keeping transformations inside the style so they survive merging.

Directives guide →

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)
    .border(.color(Colors.red));

Utility-first overview →

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 #

Contributors #

416
likes
0
points
20.1k
downloads

Publisher

verified publisherleoafarias.com

Weekly Downloads

An expressive way to effortlessly build design systems in Flutter.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, mix_annotations

More

Packages that depend on mix