auto_theme
auto_theme lets you design your Flutter app in one mode and automatically get
the opposite mode for free.
Build a light theme and it generates the dark theme. Build a dark theme and it generates the light theme.
Screenshots
| Light mode | Auto-generated dark mode |
|---|---|
![]() |
![]() |
Why use it
- Start with a single
ThemeData - Get both
themeanddarkTheme - Works with Material 3 and
ColorScheme - Includes runtime theme switching
- Ships with a simple
MaterialAppwrapper - Still lets you override the generated opposite theme when needed
Best fit
auto_theme works best when your app already uses Flutter theming properly:
ThemeDataColorScheme- Material component themes like
AppBarTheme,CardTheme, andInputDecorationTheme
If your widgets use lots of hardcoded colors, custom painting, or branded image assets, you should expect a little manual cleanup for perfect results.
Installation
dependencies:
auto_theme: ^0.1.0
Quick start
Wrap your app and provide only one theme:
import 'package:auto_theme/auto_theme.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return AutoThemeApp.materialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
brightness: Brightness.light,
),
),
home: const HomePage(),
);
}
}
That single theme becomes:
themewhen the source theme is lightdarkThemewhen the source theme is dark- an auto-generated opposite theme for the other side
Builder usage
Use the builder constructor if you want full control over MaterialApp:
AutoThemeApp(
theme: myDarkTheme,
initialThemeMode: ThemeMode.dark,
builder: (context, lightTheme, darkTheme, themeMode) {
return MaterialApp(
theme: lightTheme,
darkTheme: darkTheme,
themeMode: themeMode,
home: const HomePage(),
);
},
);
Generate only the opposite theme
If you don't want the wrapper widget, generate the missing theme directly:
final darkTheme = ThemeGenerator.generateOpposite(myLightTheme);
Programmatic control
Access the controller anywhere below AutoThemeApp:
final controller = AutoThemeApp.of(context);
controller.toggle();
controller.setLight();
controller.setDark();
controller.setSystem();
Ready-made toggle widgets
Use the included switch in an app bar:
AppBar(
actions: const [
AutoThemeSwitch(includeSystem: true),
],
)
Or use the switch-style toggle:
const AutoThemeToggle()
Provide your own opposite theme
If the generated theme gets you 90% of the way there, you can still inject a hand-tuned opposite theme:
AutoThemeApp.materialApp(
theme: myLightTheme,
oppositeTheme: myDarkTheme,
home: const HomePage(),
)
How it works
auto_theme doesn't do a naive RGB inversion. It retunes colors by role:
- Backgrounds become appropriate light or dark surfaces
- Accent colors keep their hue but shift to more usable lightness values
- Text colors are adjusted for readability
- Contrast is checked and corrected where possible
- Common Material theme sections are mapped into the generated theme
Example app
A complete demo is included in example/lib/main.dart.
Run it with:
cd example
flutter run -d macos

