fluttersdk_wind 1.0.0-alpha.4
fluttersdk_wind: ^1.0.0-alpha.4 copied to clipboard
Utility-first styling framework for Flutter inspired by Tailwind CSS. Build UIs with WDiv, WText, WButton using intuitive className syntax.
[Wind Logo]
Wind
Utility-first styling for Flutter, inspired by Tailwind CSS.
Build beautiful, responsive UIs with familiar className syntax — no more nested style objects.
Documentation · Playground · pub.dev · Issues
Alpha Release — v1 is under active development. APIs may change before stable. Star the repo to follow progress.
Why Wind? #
Flutter's styling is powerful but verbose. A simple card with padding, rounded corners, and a shadow requires deeply nested Container, BoxDecoration, EdgeInsets, and BorderRadius objects.
Wind fixes this. Write the same UI in one line:
// Before — Flutter way
Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [BoxShadow(blurRadius: 10, color: Colors.black12)],
),
child: Text('Hello', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
)
// After — Wind way
WDiv(
className: 'bg-white rounded-xl shadow-lg p-6',
child: WText('Hello', className: 'text-xl font-bold'),
)
If you know Tailwind CSS, you already know Wind.
Features #
| Feature | Description | |
|---|---|---|
| 🧩 | 20 Widgets | WDiv, WText, WButton, WInput, WSelect, WPopover, WDynamic and more |
| 🎨 | Tailwind Syntax | Same utility classes: flex, p-4, bg-blue-500, rounded-lg, shadow-md |
| 📱 | Responsive | sm:, md:, lg:, xl:, 2xl: breakpoint prefixes |
| 🌙 | Dark Mode | dark: prefix with runtime toggle via context.windTheme.toggleTheme() |
| 🎯 | State Styling | hover:, focus:, disabled:, loading:, and custom state prefixes |
| 🔌 | Platform Prefixes | ios:, android:, web:, mobile: conditional styling |
| 🎭 | Theme System | Customizable token scales — colors, spacing, typography, shadows, and more |
| 📡 | Server-Driven UI | WDynamic renders widget trees from JSON — build UIs without app updates |
Quick Start #
1. Install #
flutter pub add fluttersdk_wind
2. Wrap with WindTheme #
import 'package:fluttersdk_wind/fluttersdk_wind.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return WindTheme(
data: WindThemeData(),
builder: (context, controller) => MaterialApp(
theme: controller.toThemeData(),
home: const HomePage(),
),
);
}
}
3. Build with className #
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: WDiv(
className: 'flex flex-col gap-6 p-6 bg-gray-50 dark:bg-gray-900 min-h-screen',
children: [
WText(
'Welcome to Wind',
className: 'text-3xl font-bold text-gray-900 dark:text-white',
),
WDiv(
className: 'bg-white dark:bg-gray-800 rounded-xl shadow-lg p-6',
child: WText(
'Utility-first styling, right in Flutter.',
className: 'text-gray-600 dark:text-gray-300',
),
),
WButton(
onTap: () => print('Wind!'),
className: 'bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg',
child: Text('Get Started'),
),
],
),
);
}
}
Widgets #
Layout & Container #
// Flex row with gap
WDiv(
className: 'flex flex-row gap-4 p-4 bg-white rounded-lg shadow',
children: [sidebar, content],
)
// Responsive grid
WDiv(
className: 'grid grid-cols-1 md:grid-cols-3 gap-6',
children: cards,
)
// Scrollable container
WDiv(
className: 'w-full h-full overflow-y-auto p-4',
child: longContent,
)
Typography #
WText('Heading', className: 'text-2xl font-bold text-gray-900 dark:text-white')
WText('Body text', className: 'text-base text-gray-600 leading-relaxed')
WText('LABEL', className: 'text-xs font-semibold uppercase tracking-wider text-gray-500')
Forms #
// Text input with focus ring
WFormInput(
label: 'Email',
value: _email,
onChanged: (v) => setState(() => _email = v),
className: 'p-3 border rounded-lg focus:ring-2 focus:ring-blue-500',
)
// Searchable dropdown
WFormSelect<String>(
label: 'Country',
value: _country,
options: countries,
onChange: (v) => setState(() => _country = v),
searchable: true,
)
// Date picker
WFormDatePicker(
label: 'Start Date',
value: _date,
onChanged: (v) => setState(() => _date = v),
)
Interactive #
// Button with loading state
WButton(
onTap: _submit,
isLoading: _isSubmitting,
className: 'bg-blue-600 hover:bg-blue-700 loading:bg-blue-400 text-white px-6 py-3 rounded-lg',
child: Text('Submit'),
)
// Popover menu
WPopover(
alignment: PopoverAlignment.bottomRight,
className: 'w-64 bg-white dark:bg-gray-800 rounded-lg shadow-xl p-2',
triggerBuilder: (context, isOpen, isHovering) => WButton(
className: 'bg-gray-100 hover:bg-gray-200 px-4 py-2 rounded-lg',
child: Text('Menu'),
),
contentBuilder: (context, close) => Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(title: Text('Profile'), onTap: close),
ListTile(title: Text('Settings'), onTap: close),
],
),
)
Media #
WIcon(Icons.star_outlined, className: 'text-yellow-500 text-3xl')
WImage(src: 'https://example.com/photo.jpg', className: 'w-full aspect-video object-cover rounded-xl')
WSvg(src: 'assets/logo.svg', className: 'fill-blue-600 w-12 h-12')
Server-Driven UI #
// Render UI from JSON — no app update needed
WDynamic(
config: WDynamicConfig.fromJson(serverResponse),
customIcons: {'app-logo': Icons.flutter_dash},
customBuilders: {'chart': (node) => MyChartWidget(node.props)},
)
Supported Utilities #
Layout — flex, grid, positioning, overflow
flex flex-row flex-col flex-wrap flex-1 grid grid-cols-{n} gap-{n} justify-center justify-between items-center items-start self-center wrap hidden overflow-hidden overflow-y-auto
Sizing — width, height, constraints
w-full w-1/2 w-[200px] h-screen h-full min-h-screen max-w-lg max-w-[600px] aspect-square aspect-video
Spacing — padding, margin
p-{n} px-{n} py-{n} pt-{n} m-{n} mx-auto mt-{n} mb-{n} -mt-{n} space-x-{n} gap-{n}
Typography — size, weight, style, alignment
text-xs text-sm text-base text-lg text-xl text-2xl text-3xl font-bold font-semibold font-medium font-light italic uppercase lowercase capitalize underline line-through truncate text-center text-right leading-tight leading-relaxed tracking-wider
Colors — background, text, border, opacity
bg-{color}-{shade} text-{color}-{shade} border-{color}-{shade} bg-[#hex] text-[#hex] bg-red-500/50 (opacity modifier) bg-transparent bg-white bg-black
Borders & Effects — radius, shadow, ring, opacity
border border-2 border-t rounded rounded-lg rounded-xl rounded-full shadow shadow-md shadow-lg shadow-xl shadow-blue-500/20 ring-2 ring-blue-500 ring-offset-2 ring-inset opacity-50
Transitions & Animations
duration-150 duration-300 duration-500 ease-in ease-out ease-in-out animate-spin animate-pulse animate-bounce animate-ping
Responsive & Conditional
Breakpoints: sm: md: lg: xl: 2xl:
Dark mode: dark:
Platform: ios: android: web: mobile:
States: hover: focus: disabled: loading: checked: selected: + custom
Dark Mode #
// Pair every color with its dark variant
WDiv(
className: 'bg-white dark:bg-gray-900 border dark:border-gray-700',
child: WText(
'Adapts automatically',
className: 'text-gray-900 dark:text-white',
),
)
// Toggle at runtime
context.windTheme.toggleTheme();
// Reset to system preference
context.windTheme.resetToSystem();
Responsive Design #
// Stack on mobile, side-by-side on desktop
WDiv(
className: 'flex flex-col md:flex-row gap-4',
children: [
WDiv(className: 'w-full md:w-1/3', child: sidebar),
WDiv(className: 'w-full md:w-2/3', child: content),
],
)
// Hide on mobile, show on desktop
WDiv(className: 'hidden md:flex', child: desktopNav)
Custom Theme #
WindTheme(
data: WindThemeData(
colors: {
'primary': MaterialColor(0xFF6366F1, {
50: Color(0xFFEEF2FF),
500: Color(0xFF6366F1),
900: Color(0xFF312E81),
}),
},
baseSpacingUnit: 4.0,
baseFontSize: 16.0,
),
builder: (context, controller) => MaterialApp(
theme: controller.toThemeData(),
home: const App(),
),
)
Use your custom colors anywhere:
WDiv(className: 'bg-primary-500 text-white p-4 rounded-lg')
Architecture #
Wind uses a modular parsing architecture — each utility domain has its own parser:
className string
↓
WindParser.parse()
↓
17 domain parsers (first match wins)
↓
WindStyle (immutable value object)
↓
Widget.build()
Parsers: background, border, display, effect, flex, font, grid, margin, opacity, overflow, padding, position, shadow, sizing, spacing, text, transition
Cache: Parsed results are cached by className + breakpoint + brightness + platform + states for zero-cost re-renders.
AI Agent Integration #
Use Wind with AI coding assistants like Claude Code, Cursor, or GitHub Copilot. The wind-ui skill teaches your AI the correct className patterns, layout rules, widget API, and common anti-patterns — so it generates correct Wind code on the first try.
Setup instructions and skill files: fluttersdk/ai
Documentation #
Full docs with live examples at wind.fluttersdk.com.
Contributing #
git clone https://github.com/fluttersdk/wind.git
cd wind && git checkout v1 && flutter pub get
flutter test && dart analyze
Report a bug · Request a feature
License #
MIT — see LICENSE for details.
Built with care by FlutterSDK
If Wind saves you time, give it a star — it helps others discover it.