New package: exui - Build Flutter UIs faster with less code, same performance, pure Dart and Flutter

A practical toolkit for Flutter UI development, focused on saving time, reducing boilerplate, and writing layout code that’s readable, consistent, and fun.

Whether you’re working on layout, spacing, visibility, or sizing, exui gives you expressive helpers for the most common tasks, with zero dependencies and seamless integration into any codebase.

Here are just a few examples:


:straight_ruler: Padding

With exui:

Text("Hello").paddingAll(16)

Without:

Padding(
  padding: EdgeInsets.all(16),
  child: Text("Hello"),
)

With additional extensions for quickly adding specific padding: paddingHorizontal, paddingVertical, paddingOnly, paddingSymmetric, paddingLeft, paddingRight, paddingTop, paddingBottom


:up_down_arrow: Gaps

exui gaps are more performant than the gap package — they use native SizedBox widgets with no runtime checks or context detection. Just pure Dart and Flutter for clean, zero-overhead spacing.
With exui:

Column(
  children: [
    Text("A"),
    16.gapColumn,
    Text("B"),
  ],
)

Without:

Column(
  children: [
    Text("A"),
    SizedBox(height: 16),
    Text("B"),
  ],
)

With additional extensions for quickly adding specific gap values: gapRow, gapColumn, gapVertical, gapHorizontal etc.


:eye: Visibility

With exui:

Text("Visible?").visibleIf(showText)

Without:

showText ? Text("Visible?") : const SizedBox.shrink()

:construction: Constraints

With exui:

Image.asset("logo.png").maxWidth(200)

Without:

ConstrainedBox(
  constraints: BoxConstraints(maxWidth: 200),
  child: Image.asset("logo.png"),
)

https://pub.dev/packages/exui


All exui Extensions:

Emojis only added to distinguish easily between extensions

Layout Manipulation

:straight_ruler: padding - Quickly Add Padding
:bullseye: center - Center Widgets
↔️ expanded - Fill Available Space
:dna: flex - fast Flexibles
:triangular_ruler: align - Position Widgets
:round_pushpin: positioned - Position Inside a Stack
:white_square_button: intrinsic - Size Widgets
:minus: margin - Add Outer Spacing

Layout Creation

:up_down_arrow: gap - Performant gaps
:brick: row / column - Rapid Layouts
:compass: row* / column* - Rapid Aligned Layouts
:ice: stack - Overlay Widgets

Visibility, Transitions & Interactions

:eye: visible - Conditional Visibility
:fog: opacity - Widget Transparency
:mobile_phone: safeArea - SafeArea Padding
:backhand_index_pointing_up: gesture - Detect Gestures
:superhero: hero - Shared Element Transitions

Containers & Effects

:package: sizedBox - Put in a SizedBox
:construction: constrained - Limit Widget Sizes
:red_square: coloredBox - Wrap in a Colored Box
:artist_palette: decoratedBox - Borders, Gradients & Effects
:scissors: clip - Clip Widgets into Shapes
:mirror: fittedBox - Fit Widgets

Click here to see the full documentation

2 Likes

Isn’t this using functions to build Widgets, which is not recommended?

Functions are “not recommended” because it does not create “another widget” / using the same build method. Therefore if you overuse it (i.e. everything is done using helper methods), it will rebuild the whole widget tree instead of optimizing rebuilds to only small parts of the widget tree. Therefore separate widgets are recommended and generally everyone should use that approach.

But when separating UI to Widgets + using it as a utility does not have these problems.
If you simply use separate widgets and combining these utilities you will not rebuild the whole tree because although the extensions are used, they are inside of a Widget that is not rebuilt.

Yep. Small utils are OK. Since they are part of the widget in the same way as widget wrapped something would be. Therefore no difference.