DEV Community

Cover image for Effortless styling in Flutter
SaltyAom
SaltyAom

Posted on

Effortless styling in Flutter

Creating a user interface shouldn't be confusing.

"Everything in Flutter is Widget" is what you usually heard. But I have a different opinion and think, the concept of Flutter itself makes it too nested and verbose.

Composing a simple Button with padding adds an extra level of nested in Layout, adding an extra maintenance effort. The representative should contain only a business logic widget, not an entire list of styling widgets.

Comparison

After a long month, that's why I create a library for that and proud to introduce the release of Niku 1.0

What is it exactly?

Niku is an effortless property builder for composing maintainable Flutter UI.

It's just like as you see from the picture above.

Removing unnecessary styling from the Widget tree itself and separates it from the main representative. Able also move into a different file and reuse styling everywhere in the codebase.

Niku uses property builder, as same as SwiftUI does. Design to be able to compose reusable style, like CSS. Use the same naming convention of TailwindCSS. And running in Flutter.

So composing your UI in Flutter should be fast and fluent while maintaining the codebase at the same time of the development process.


Property Builder

Composing a button using Niku is as simple as:

NikuButton(
  Text("A flat button")
)
  ..fontSize(21)
  ..fg(Colors.white)   // Foreground, eg. text color (idiomatic Flutter)
  ..bg(Colors.blue);   // Background, color of button  
Enter fullscreen mode Exit fullscreen mode

Shorten Syntax

Or a long styling of an outlined textfield is compact into a simple custom property like:

NikuTextField()
  ..outlined(width: 4)
  ..borderColor(
    enabled: Colors.blue,
  )
  ..color(Colors.white);
Enter fullscreen mode Exit fullscreen mode

Which is an equivalent to this in Flutter:

TextFormField(
    style: TextStyle(
    color: Colors.blue,
  ),
  decoration: InputDecoration(
    border: OutlineInputBorder(
      borderSide: BorderSide(
        color: Colors.grey,
        width: 2,
        style: BorderStyle.solid,
      ),
      borderRadius: BorderRadius.all(Radius.circular(8)),
      gapPadding: 4,
    ),
    enabledBorder: OutlineInputBorder(
      borderSide: BorderSide(
        color: Colors.blue,
        width: 2,
        style: BorderStyle.solid,
      ),
      borderRadius: BorderRadius.all(Radius.circular(8)),
      gapPadding: 4,
    ),
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(
        color: Colors.grey,
        width: 2,
        style: BorderStyle.solid,
      ),
      borderRadius: BorderRadius.all(Radius.circular(8)),
      gapPadding: 4,
    ),
    errorBorder: OutlineInputBorder(
      borderSide: BorderSide(
        color: Colors.red,
        width: 2,
        style: BorderStyle.solid,
      ),
      borderRadius: BorderRadius.all(Radius.circular(8)),
      gapPadding: 4,
    ),
    focusedErrorBorder: OutlineInputBorder(
      borderSide: BorderSide(
        color: Colors.red,
        width: 2,
        style: BorderStyle.solid,
      ),
      borderRadius: BorderRadius.all(Radius.circular(8)),
      gapPadding: 4,
    ),
    disabledBorder: OutlineInputBorder(
      borderSide: BorderSide(
        color: Colors.grey,
        width: 2,
        style: BorderStyle.solid,
      ),
      borderRadius: BorderRadius.all(Radius.circular(8)),
      gapPadding: 4,
    ),
  ),
);
Enter fullscreen mode Exit fullscreen mode

Reusable Style

Niku's best feature is being able to compose and reuse defined style anywhere like CSS.
So you don't have to rewrite the entire nested widget for just styling widget which has a little different styling.

// Somewhere
final systemTextField = NikuTextField()
  ..outlined(width: 4)
  ..borderColor(
    enabled: Colors.blue,
  )
  ..color(Colors.white);

// Widget 1
return NikuColumn([
  NikuTextField()
    ..apply(systemTextField),
  NikuTextField()
    ..apply(systemTextField)
    ..borderColor(
      enabled: Colors.green,
    ),
]);
Enter fullscreen mode Exit fullscreen mode

Parent Builder

Not only Niku supports styling of predefined Widgets.
But also nest any Widget with parent property builder.

Niku(
  ThirdPartyWidget(),
)
  ..my(20).  // Margin Y (Tailwind Convention)
  ..bg(Colors.black.withOpacity(.2))
  ..builder(customBuilder);
Enter fullscreen mode Exit fullscreen mode

Release today

Niku has just released version 1.0.0 and you can try it out today!

No code generation.
No dependency.
With Flutter 2 support and null sound safety.
Very low learning curve.
From what you've already known.

Niku can easily integrate with any codebase!

You can easily install Niku from pub.dev like any other dependency.


Afterword

Niku is inspired by SwiftUI, Tailwind CSS.
An Apple developer or web developer will be very familiar with Niku and already known half of Niku and ready to pick up.

Niku brings the best of both worlds. Packed into familiar API and shipped directly into Flutter while being idiomatic to Dart.

Niku is designed to help you to make Flutter easier and more maintainable.
It's like a missing piece in Flutter for me, and I want it to be for you too.

You can support Niku on GitHub or explore more in Niku Documentation.

Thank you for your attention, see you in the next post~

Feels free to add any idea or opinion, it's going to help the development direction a lot!

Top comments (3)

Collapse
 
gochev profile image
Nayden Gochev • Edited

Also why this is called .niku() to call the parent instead of just parent() or parentStyle() or something it is super strange to have the niku method.

But in any case GREAT work .. looking forward for this project.

Collapse
 
gochev profile image
Nayden Gochev

How does it compare with Division ?

Collapse
 
avkonst profile image
Andrey

Very nice. There is also velocityx with similar features.