Dark Mode
Switch your entire app between light and dark themes with a single call. Wind automatically inverts every color in your palette, so widgets styled with bg-gray-200 or text-black adapt to dark mode without rewriting their class names.
- Basic Usage
- How It Works
- The
dark:Prefix - Keeping Colors Static
- Best Practices
- Related Documentation
import 'package:flutter/material.dart';
import 'package:fluttersdk_wind/fluttersdk_wind.dart';
class DarkMode extends StatefulWidget {
const DarkMode({super.key});
@override
State createState() => _DarkModeState();
}
class _DarkModeState extends State {
void enableDarkMode() {
setState(() {
WindTheme.setType(Brightness.dark);
});
}
@override
Widget build(BuildContext context) {
return WCard(
className: 'shadow-lg rounded-lg p-4 bg-white',
child: WFlex(
className: 'flex-col axis-min gap-2 items-start',
children: [
WText('12', className: 'text-4xl leading-6 font-bold text-black'),
WText('Active users on the website', className: 'text-black leading-4'),
],
),
);
}
}
Basic Usage
Dark mode is driven entirely by WindTheme. Call WindTheme.setType(Brightness.dark) to switch the active brightness, then rebuild the widget tree so the new colors take effect:
setState(() {
WindTheme.setType(Brightness.dark);
});
To follow the platform brightness instead of toggling manually, derive it from the current BuildContext:
WindTheme.setTypeFromContext(context);
You never list a separate dark palette. The colors you already use (bg-white, text-black, bg-gray-200) are inverted automatically the moment the brightness changes.
How It Works
When you call setType, Wind runs WindTheme.generateDarkenColors() under the hood. For every registered color it swaps the shade scale end-for-end, so the lightest shade becomes the darkest and vice versa:
| Light value | Inverted dark value |
|---|---|
gray-50 |
gray-900 |
gray-200 |
gray-700 |
gray-500 |
gray-400 |
gray-800 |
gray-100 |
white |
a near-black surface |
black |
white |
The result is that a card styled bg-white reads as a dark surface and text-black reads as near-white once dark mode is active, with no extra class names. Switching back to Brightness.light restores the original palette.
The dark: Prefix
When automatic inversion is not enough and you want an explicit dark-mode-only value, prefix any utility with dark:. Wind applies the prefixed class only while WindTheme.getType() returns Brightness.dark:
WCard(
className: 'p-4 rounded-lg bg-white dark:bg-gray-800',
child: WText(
'Adapts on its own, overridden explicitly when needed.',
className: 'text-gray-900 dark:text-white',
),
);
The dark: prefix and its light: counterpart are resolved by the screens parser, alongside the responsive sm:/md:/lg: breakpoints. See Responsive Design for the full prefix model.
Keeping Colors Static
Some colors, a brand accent for example, should look identical in both modes. Register them with WindTheme.addStaticColor so they are excluded from the inversion pass:
WindTheme.addStaticColor('primary');
WindTheme.addStaticColor('secondary');
A static color keeps the same shade scale regardless of the active brightness. Call WindTheme.removeStaticColor('primary') to opt it back into inversion.
Best Practices
- Toggle inside
setState(or your state-management rebuild path) so the tree repaints with the inverted palette. - Prefer automatic inversion first; reach for the
dark:prefix only when a specific value should differ from the inverted default. - Mark brand and accent colors static with
addStaticColorso they stay recognizable across both modes. - Use
setTypeFromContextwhen you want Wind to follow the system orMaterialAppbrightness rather than a manual toggle.
Related Documentation
- Responsive Design — the prefix model
dark:shares with breakpoints. - State-Based Styling — applying styles for widget states such as
hoveranddisabled. - Colors — registering palette colors and reading them with
wColor. - Background Color — the
bg-*utilities that benefit from inversion.