DEV Community

Cover image for Flutter Design Systems: Exploring Modern Alternatives to Material Design
Dinko Marinac
Dinko Marinac

Posted on • Originally published at dinkomarinac.dev

Flutter Design Systems: Exploring Modern Alternatives to Material Design

Introduction

Design systems are essential frameworks that ensure consistency and coherence in application development, providing a unified language for designers and developers. They encompass guidelines, components, and tools that streamline the design and implementation process.

In Flutter, Material Design is the default design system, deeply integrated to provide a seamless development experience. However, while Material Design offers a robust set of components and styling options, it can sometimes be restrictive or verbose, making customization and extension challenging.

This article explores alternative design systems for Flutter that address these limitations, offering more flexibility, ease of use, and unique features that cater to diverse project needs.

Mix

Mix is an expressive styling system for Flutter which takes inspiration from Tailwind CSS. The idea is to reduce the verbosity of Flutter's default styling system by bundling all the styling into a single variable and applying it to the view.

Other mobile declarative frameworks like Jetpack Compose and SwiftUI take a very similar approach*. C*ommon things like paddings, margins, background colors, view shape, and clickability are all applied through view modifiers.

Mix is designed to be utility-first and provides simple and low-level utilities for you to use it directly or create your own design system based on it.

How styling with Mix look like?

In Flutter, you might style a Container with elevation and color like this:

Container(
  height: 100,
  width: 100,
  margin: EdgeInsets.symmetric(
    vertical: 10,
    horizontal: 20,
  ),
  decoration: BoxDecoration(
    color: Colors.blue,
    borderRadius: BorderRadius.circular(10),
    border: Border.all(
      color: Colors.black,
      width: 1,
      style: BorderStyle.solid,
    ),
  ),
  child: Text('Container'),
);
Enter fullscreen mode Exit fullscreen mode

This is how it would look like with Mix:

final style = Style(
  $box.height(100),
  $box.width(100),
  $box.margin(10, 20),
  $box.color.blue(),
  $box.borderRadius(10),
  $box.border(
    color: Colors.black,
    width: 1,
    style: BorderStyle.solid,
  ),
);

Box(
  style: style,
  child: Text('Hello Mix'),
);
Enter fullscreen mode Exit fullscreen mode

The biggest difference to the Flutter styling system is that Mix uses a Style class which encompasses all available styling for that specific class. Styles can be extended, modified, and composed.

final baseStyle = Style(
  $box.height(100),
  $box.width(100),
  $box.color.purple(),
  $box.borderRadius(10),
);

// extend base style with new properties
final newStyle = baseStyle.add(
  $box.border.width(2),
  $box.border.color.black(),
);

// modify the color
final newStyleColored = baseStyle.add(
  $box.color.blue(),
);

// combine and merge styles
final borderStyle = Style(
  $box.border.width(2),
  $box.border.color.black(),
);

final baseBorderedStyleCombined = Style.combine([
  baseStyle,
  borderStyle,
]);

final baseBorderedStyleMerged = baseStyle.merge(borderStyle);
Enter fullscreen mode Exit fullscreen mode

Mix goes a step further in developer experience with a system to create widget variants and widget modifiers.

Remember all the times that you wanted to have one widget that has the exact same functionality, but just different enough styling that now it needs a completely different Widget implementation? Mix solves that very elegantly because each variant can have its own Style class instead of creating different widgets because the order of widgets is different.

The last feature I want to highlight is the ability to create widget modifiers. Instead of wrapping your widgets with another widget just to add padding or clickability, you can create a modifier that will do the same thing under the hood for you. This gets rid of the mess that deeply nested widgets create.

Mix comes with a predefined set of very common widget modifiers like scale, opacity, aspect ratio, clip, visibility, and others that turn your code from this:

Visibility(
  visible: false,
  child: Box(
    child: const Text('Invisible box'),
  ),
);
Enter fullscreen mode Exit fullscreen mode

to this:

final style = Style(
  $with.visibility(false),
);

Box(
  style: style,
  child: const Text('Invisible box'),
);
Enter fullscreen mode Exit fullscreen mode

Mix is the most promising and welcome change to the world of Flutter styling in years. The author has also mentioned that there is an official design system called Remix UI that’s in the works.

Shadcn

Shadcn is the Flutter port of the super popular UI toolkit shadcn/ui.

The idea behind the original Shadcn is that it’s not just a component library you import and use and you have a hard time building upon it because of the provided APIs. It’s a set of reusable components you can copy and paste into your app to create your design system and your own component library.

The Flutter port provides you with a customizable component library which you can build on top of, but because it’s open source, nothing stops you from copy-pasting the code into your project.

To keep compatibility with the original Flutter App API, Shadcn offers 3 different app constructors:

  • ShadApp - used to run pure Shadcn styling system
  • ShadApp.material - used to run Shadcn along Material
  • ShadApp.cupertino - used to run Shadcn along Cupertino

Having all 3 of them enables you to migrate gradually over the course of months or just use the components you like.

Theme data is inspired by the Material, enabling you to use the existing knowledge to style the app. The difference comes from the ShadDecoration, which is responsible for the styling of the most components library provides.

Components range from simple ones like buttons and switches to more complicated ones like resizable panels, tables, and sheets (bottom, top, side).

The documentation comes with a preview and the code for all the components, which makes it easy for anybody to pick up the library and start building.

Moon & Modular UI

Moon and Modular UI are UI kits created to streamline development efforts by providing frequently used components. They are based on their respective design system, but they are not as powerful as the ones specified before.

Moon

Moon is a design system created by the YoloGroup. They use it for all their product and the design system spans multiple programming languages.

The Flutter package is actually a UI kit that comes with prebuilt components ready to kickstart the process of building the UI. It consists of primitive components like Alert, Avatar, Accordion, Button, Chip, and composite components like search with a list of multi-select combo box.

The theming is done through a ThemeExtension, making it compatible with the tight coupling Flutter has with Material.

final lightTokens = MoonTokens.light.copyWith(
  colors: MoonColors.light.copyWith(
    piccolo: Colors.blue,
    textPrimary: Colors.amber,
  ),
  typography: MoonTypography.typography.copyWith(
    heading: MoonTypography.typography.heading.apply(fontFamily: "DMSans"),
  ),
);

final lightTheme = ThemeData.light().copyWith(
    extensions: <ThemeExtension<dynamic>>[MoonTheme(tokens: lightTokens)],
  );
Enter fullscreen mode Exit fullscreen mode

Moon’s documentation also comes with a preview of all of the widgets included and enables you to see and customize the components.

Modular UI

Modular UI is a set of pre-built Flutter widgets Inspired by material-tailwind and Shadcn.

The kit consists of commonly used components like alerts, buttons, tab bars, switches, and sliders, but also comes with more complex components like carousel, sign-in card, and sign-up card which enable you to create very common UI and flow elements very quickly.

Conclusion

Material Design remains a powerful and integral part of Flutter, but alternative design systems like Mix, Shadcn, Moon, and Modular UI offer compelling solutions for those who seek more flexibility and simplicity in their projects.

Mix, with its Tailwind CSS-inspired utility-first approach, significantly reduces the verbosity of Flutter's default styling. Shadcn provides a versatile component library that integrates seamlessly with Material or Cupertino, allowing for gradual migration and customization. Moon and Modular UI streamline development with pre-built components based on their respective design systems, catering to primitive and complex UI needs.

If you still prefer to work within the Material Design framework but seek enhanced customization, I would recommend FlexColorScheme, a package that simplifies the process of implementing complex color schemes for Material Design in Flutter, offering more flexibility and extensibility.

If you have found this useful, make sure to like and follow for more content like this. To know when the new articles are coming out, follow me on Twitter and LinkedIn.

Until next time, happy coding!

Top comments (0)