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

Design Tokens

Design tokens define visual properties (colors, typography, spacing) in a centralized way. Mix provides built-in support through MixToken and MixScope.

Getting Started

Mix tokens are defined as key-value pairs where the key is a class that extends MixToken<T> and the value is the actual resolved value.

import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; // 1. Declare the token final $primary = ColorToken('primary'); // 2. Define the token value in MixScope MixScope( colors: { $primary: Colors.lightBlue, }, child: MyApp(), ); // 3. Use the token in a style final style = BoxStyler() .color($primary()) // Use call() to reference the token .size(100, 100);

MixScope

MixScope is the widget that provides token values to all its descendants. It works similar to Flutter’s Theme and ThemeData pattern.

import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MixScope( colors: { $primary: Colors.blue, $secondary: Colors.green, $background: Colors.white, }, spaces: { $spacingSm: 8.0, $spacingMd: 16.0, $spacingLg: 24.0, }, radii: { $radiusSm: Radius.circular(4), $radiusMd: Radius.circular(8), }, child: MaterialApp( home: MyHomePage(), ), ); } }

Built-in Token Types

Mix provides several built-in token types for common styling needs:

Token TypeValue TypeUse Case
ColorTokenColorColors and backgrounds
SpaceTokendoubleSpacing values (padding, margin)
DoubleTokendoubleAny numeric value
RadiusTokenRadiusBorder radii
TextStyleTokenTextStyleTypography styles
BorderSideTokenBorderSideBorder definitions
ShadowTokenList<Shadow>Text shadows
BoxShadowTokenList<BoxShadow>Box shadows
FontWeightTokenFontWeightFont weights
DurationTokenDurationAnimation durations
BreakpointTokenBreakpointResponsive breakpoints

Token Examples

import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; // Color tokens final $primary = ColorToken('color.primary'); final $secondary = ColorToken('color.secondary'); final $error = ColorToken('color.error'); // Spacing tokens final $spacingSm = SpaceToken('spacing.sm'); final $spacingMd = SpaceToken('spacing.md'); final $spacingLg = SpaceToken('spacing.lg'); // Radius tokens final $radiusSm = RadiusToken('radius.sm'); final $radiusMd = RadiusToken('radius.md'); // Typography tokens final $headingStyle = TextStyleToken('typography.heading'); final $bodyStyle = TextStyleToken('typography.body'); // Duration tokens final $durationFast = DurationToken('duration.fast'); final $durationNormal = DurationToken('duration.normal'); // Provide values in MixScope MixScope( colors: { $primary: Colors.blue, $secondary: Colors.green, $error: Colors.red, }, spaces: { $spacingSm: 8.0, $spacingMd: 16.0, $spacingLg: 24.0, }, radii: { $radiusSm: Radius.circular(4), $radiusMd: Radius.circular(8), }, textStyles: { $headingStyle: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), $bodyStyle: TextStyle(fontSize: 16), }, child: MyApp(), );

Using Tokens in Styles

Call Syntax

Use ${token_name}.call() or ${token_name}() to reference a token:

final style = BoxStyler() .color($primary()) .paddingAll($spacingMd());

Token Methods

Some stylers provide dedicated token methods:

final style = BoxStyler() .colorToken($primary) .paddingToken($spacingMd);

Prop.token

Use Prop.token() with .create() constructors for advanced composition:

final style = BoxStyler.create( color: Prop.token($primary), padding: Prop.token($spacingMd), );

Creating Custom Tokens

You can create custom token types for values not covered by built-in tokens. To create a custom token:

  1. Extend MixToken<T> with your value type
  2. Override the call() method to return a reference type

Example: EdgeInsetsGeometry Token

import 'package:flutter/widgets.dart'; import 'package:mix/mix.dart'; /// Token for EdgeInsetsGeometry values class EdgeInsetsGeometryToken extends MixToken<EdgeInsetsGeometry> { const EdgeInsetsGeometryToken(super.name); @override EdgeInsetsGeometryRef call() => EdgeInsetsGeometryRef(Prop.token(this)); } /// Reference class for EdgeInsetsGeometry tokens class EdgeInsetsGeometryRef extends Prop<EdgeInsetsGeometry> { EdgeInsetsGeometryRef(Prop<EdgeInsetsGeometry> prop) : super.fromProp(prop); }

Using the Custom Token

// Declare the token final $contentPadding = EdgeInsetsGeometryToken('padding.content'); final $cardPadding = EdgeInsetsGeometryToken('padding.card'); // Provide values in MixScope MixScope( // Custom tokens use the generic tokens map tokens: { $contentPadding: EdgeInsets.all(16), $cardPadding: EdgeInsets.symmetric(horizontal: 24, vertical: 16), }, child: MyApp(), ); // Use with BoxStyler.create final style = BoxStyler() .color(Colors.red) .size(100, 100) .merge(BoxStyler.create(padding: $contentPadding()));

For most use cases, the built-in token types cover common styling needs. Only create custom tokens when you need specialized value types.

Theme Switching

Tokens enable theme switching by providing different values in different contexts:

import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; // Define tokens final $background = ColorToken('background'); final $foreground = ColorToken('foreground'); final $surface = ColorToken('surface'); // Light theme values final lightTheme = { $background: Colors.white, $foreground: Colors.black, $surface: Colors.grey[100]!, }; // Dark theme values final darkTheme = { $background: Colors.grey[900]!, $foreground: Colors.white, $surface: Colors.grey[800]!, }; class ThemedApp extends StatefulWidget { @override State<ThemedApp> createState() => _ThemedAppState(); } class _ThemedAppState extends State<ThemedApp> { bool isDark = false; @override Widget build(BuildContext context) { return MixScope( colors: isDark ? darkTheme : lightTheme, child: MaterialApp( home: Scaffold( body: Box( style: BoxStyler().color($background()), child: Column( children: [ StyledText( 'Hello, World!', style: TextStyler().color($foreground()), ), ElevatedButton( onPressed: () => setState(() => isDark = !isDark), child: Text('Toggle Theme'), ), ], ), ), ), ), ); } }

Resolving Tokens Programmatically

You can resolve tokens outside of styles using BuildContext:

@override Widget build(BuildContext context) { // Resolve a token to get its value final primaryColor = $primary.resolve(context); final spacing = $spacingMd.resolve(context); return Container( color: primaryColor, padding: EdgeInsets.all(spacing), child: Text('Resolved tokens'), ); }

Best Practices

  • Use descriptive, hierarchical names: $colorPrimary, $spacingMd
  • Group related tokens in separate files (tokens/colors.dart, tokens/spacing.dart)
  • Replace hardcoded values with semantic tokens