Flutter Dark Mode

Implementing beautiful dark themes for better user experience

🌙 What is Dark Mode?

Dark mode provides a darker color scheme that reduces eye strain in low-light environments and saves battery on OLED screens. Flutter makes it easy to implement dark themes that automatically adapt to system preferences or allow users to manually toggle between light and dark modes.


MaterialApp(
  theme: ThemeData.light(),
  darkTheme: ThemeData.dark(),
  themeMode: ThemeMode.system,
  home: MyHomePage(),
)
                                    

Output (Dark Mode):

Dark Mode App
Content in dark theme

Dark Mode Features

🌓

System Theme

Follow device theme settings

MaterialApp(
  themeMode: ThemeMode.system,
  theme: ThemeData.light(),
  darkTheme: ThemeData.dark(),
)
🎨

Custom Dark Theme

Create custom dark colors

ThemeData.dark().copyWith(
  primaryColor: Colors.teal,
  scaffoldBackgroundColor: 
    Color(0xFF121212),
)
🔄

Toggle Theme

Switch between themes manually

IconButton(
  icon: Icon(Icons.brightness_6),
  onPressed: () {
    // Toggle theme
  },
)
💾

Save Preference

Remember user's theme choice

SharedPreferences prefs = 
  await SharedPreferences.getInstance();
prefs.setBool('isDark', true);

🔹 Basic Dark Mode Setup

Implement dark mode with system theme detection:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dark Mode App',
      
      // Light theme
      theme: ThemeData(
        brightness: Brightness.light,
        primarySwatch: Colors.blue,
        scaffoldBackgroundColor: Colors.white,
      ),
      
      // Dark theme
      darkTheme: ThemeData(
        brightness: Brightness.dark,
        primarySwatch: Colors.blue,
        scaffoldBackgroundColor: Color(0xFF121212),
      ),
      
      // Follow system theme
      themeMode: ThemeMode.system,
      
      home: MyHomePage(),
    );
  }
}

Output:

Light Mode
Content
Dark Mode
Content

🔹 Custom Dark Theme

Create a beautiful custom dark theme:

ThemeData darkTheme = ThemeData(
  brightness: Brightness.dark,
  
  // Primary colors
  primaryColor: Colors.teal,
  colorScheme: ColorScheme.dark(
    primary: Colors.teal,
    secondary: Colors.tealAccent,
    surface: Color(0xFF1E1E1E),
    background: Color(0xFF121212),
  ),
  
  // Scaffold
  scaffoldBackgroundColor: Color(0xFF121212),
  
  // App bar
  appBarTheme: AppBarTheme(
    backgroundColor: Color(0xFF1E1E1E),
    elevation: 0,
  ),
  
  // Card
  cardTheme: CardTheme(
    color: Color(0xFF1E1E1E),
    elevation: 2,
  ),
  
  // Text
  textTheme: TextTheme(
    bodyLarge: TextStyle(color: Colors.white),
    bodyMedium: TextStyle(color: Colors.white70),
  ),
)

Output:

Custom Dark Theme
Card Title
Card content with custom dark colors

🔹 Theme Toggle with State

Allow users to manually switch themes:

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State {
  ThemeMode _themeMode = ThemeMode.system;

  void toggleTheme() {
    setState(() {
      _themeMode = _themeMode == ThemeMode.light 
        ? ThemeMode.dark 
        : ThemeMode.light;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: _themeMode,
      home: Scaffold(
        appBar: AppBar(
          title: Text('Theme Toggle'),
          actions: [
            IconButton(
              icon: Icon(Icons.brightness_6),
              onPressed: toggleTheme,
            ),
          ],
        ),
        body: Center(child: Text('Toggle theme with button')),
      ),
    );
  }
}

Output:

Theme Toggle ☀️
Toggle theme with button

🔹 Detecting Current Theme

Check if dark mode is active in your widgets:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Check if dark mode is active
    bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
    
    return Container(
      color: isDarkMode ? Colors.grey[900] : Colors.white,
      child: Text(
        'Current theme: ${isDarkMode ? "Dark" : "Light"}',
        style: TextStyle(
          color: isDarkMode ? Colors.white : Colors.black,
        ),
      ),
    );
  }
}

// Or use MediaQuery
bool isDarkMode = MediaQuery.of(context).platformBrightness == Brightness.dark;

Output:

Current theme: Light
Current theme: Dark

🔹 Dark Mode Best Practices

Design Tips:

  • Use true black sparingly: #121212 is better than #000000 for OLED screens
  • Reduce elevation: Lower shadows in dark mode for better visibility
  • Adjust colors: Desaturate bright colors to reduce eye strain
  • Maintain contrast: Ensure text is readable with sufficient contrast
  • Test thoroughly: Check all screens in both light and dark modes
// Good dark mode colors
Color darkBackground = Color(0xFF121212);  // Not pure black
Color darkSurface = Color(0xFF1E1E1E);     // Slightly lighter
Color darkText = Colors.white;             // High contrast
Color darkTextSecondary = Colors.white70;  // Lower contrast

// Adjust elevation for dark mode
Card(
  elevation: isDarkMode ? 2 : 4,
  child: Container(...),
)

🧠 Test Your Knowledge

Which ThemeMode follows the device's system theme?