search ESC

Searching…

No results for "".

Type at least 2 characters to search.

Docs
You are viewing an older version (0.0.5). Go to the latest.

Utility-First

Utility-first is a design methodology built on small, single-purpose classes that compose into complex designs. Wind brings this approach to Flutter: instead of writing custom styles for every component, you build interfaces directly from utility classes in a className.

import 'package:flutter/material.dart';
import 'package:fluttersdk_wind/fluttersdk_wind.dart';

class UtilityFirstWind extends StatelessWidget {
  const UtilityFirstWind({super.key});

  @override
  Widget build(BuildContext context) {
    return WCard(
      className: 'shadow-lg rounded-lg m-4 p-4 bg-black',
      child: WFlex(
        className: 'flex-col axis-min gap-2 items-start',
        children: [
          WText('12', className: 'text-4xl leading-6 font-bold text-white'),
          WText('Active users on the website', className: 'text-white leading-4'),
          WText(
            'Composed entirely from utility classes.',
            className: 'text-gray-300 text-xs',
          ),
        ],
      ),
    );
  }
}

Basic Usage

Every visual decision is expressed as a utility class in className. Spacing, color, typography, and radius all live in one place, so you read the styling without jumping between widget constructors:

WCard(
  className: 'shadow-lg rounded-lg p-4 bg-black',
  child: WText('Styled in one line.', className: 'text-white text-lg font-bold'),
);

The Flutter Way

Plain Flutter spreads styling across nested constructors and TextStyle objects. The same card requires explicit Card, Padding, Column, and per-Text styles:

import 'package:flutter/material.dart';

class UtilityFirstFlutter extends StatelessWidget {
  const UtilityFirstFlutter({super.key});

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(16),
      color: Colors.black,
      elevation: 8,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(8),
      ),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text(
              '12',
              style: TextStyle(
                fontSize: 36,
                fontWeight: FontWeight.bold,
                color: Colors.white,
                height: 1.5,
              ),
            ),
            const SizedBox(height: 4),
            const Text(
              'Active users on the website',
              style: TextStyle(fontSize: 14, color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}

The Wind Way

Wind collapses that structure into utility classes on Wind widgets. The intent reads in a single glance and stays consistent because the same tokens map to the same theme values everywhere:

WCard(
  className: 'shadow-lg rounded-lg m-4 p-4 bg-black',
  child: WFlex(
    className: 'flex-col axis-min gap-2 items-start',
    children: [
      WText('12', className: 'text-4xl leading-6 font-bold text-white'),
      WText('Active users on the website', className: 'text-white leading-4'),
    ],
  ),
);

Why Utility-First

  • Consistency. Tokens resolve to theme values (bg-black, text-4xl, rounded-lg), so every screen pulls from the same scale instead of one-off magic numbers.
  • Speed. You style in place without defining a custom widget or TextStyle for each variation.
  • Readability. The full visual definition lives on one line next to the structure it styles.
  • Adaptivity. The same tokens compose with dark:, breakpoint, and state prefixes, so one class string covers multiple contexts.

Best Practices

  • Reach for utility classes first; extract a custom widget only when a composition repeats across the app.
  • Group related tokens in a readable order (layout, spacing, color, typography) inside the className.
  • Lean on theme tokens (bg-gray-200, text-lg) over arbitrary values so dark-mode inversion and theming stay coherent.
  • Pair color tokens with their dark: counterparts where a value should not rely on automatic inversion.