> For the complete documentation index, see [llms.txt](https://wong-coupon.gitbook.io/flutter/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wong-coupon.gitbook.io/flutter/ui/dark-mode.md).

# Dark Mode

## **Setting Up Light/Dark Mode**

The theme mode will be divided into three options:

* **Light Mode**
* **Dark Mode**
* **System Mode** (which follows the system settings)

However, the actual UI will only display two primary modes: **Light** and **Dark**.

```dart
extension MyThemeModeContext on BuildContext {
  bool get isDarkMode => switch (myThemeMode) {
    ThemeMode.system => MediaQuery.of(this).platformBrightness == Brightness.dark,
    ThemeMode.light => false,
    ThemeMode.dark => true,
  };
}
```

#### Creating a Global Variable to Manage Themes

We will define a global variable to manage the application's theme:

```dart
ThemeMode myThemeMode = ThemeMode.system;
```

**Handling Theme Persistence**

A common issue with this approach is that the theme setting will not persist after the app is completely closed. There are several solutions to this problem:

1. **Using `shared_preferences`** – A package that allows saving and retrieving values when initializing the app. [Learn more here](https://pub.dev/packages/shared_preferences).
2. **Storing the Theme in a BLoC State** – This ensures that the theme is managed within the state management logic.

Example of storing the theme in a `Bloc`:

```dart
myThemeMode = context.select((SettingBloc bloc) => bloc.state.settingWeb.theme);
```

For more details on how to persist values using BLoC, check out my article on the topic here.

{% content-ref url="/pages/V3SeIz7l08DCG5hi9prc" %}
[Bloc](/flutter/state-management/bloc.md)
{% endcontent-ref %}

## Applying Light and Dark Themes in the UI

**Defining Theme-Specific Colors**

Each theme (light and dark) has its own set of colors. We can determine which color to use based on the theme mode.

```dart
extension WebColorContext on BuildContext {
  Color get white => isDarkMode ? WebColor.blackForDark : WebColor.white;
}
```

**How to Use**

```dart
context.white
```

**Handling `context` Accessibility**

One potential issue with this approach is that `context` is required to access theme-specific colors, which may not always be convenient.

I have a simple way to access `context` from anywhere in the project. Check out my article for more details:

{% content-ref url="/pages/MnpADg71Yuu0vcuuCWTo" %}
[Context Anywhere](/flutter/state-management/context-anywhere.md)
{% endcontent-ref %}

## Switching Between Light and Dark Themes

To change the theme mode, use the following code:

```dart
myThemeMode = ThemeMode.light;
await WidgetsFlutterBinding.ensureInitialized().performReassemble();
```

The second line forces the entire application to redraw the screen, ensuring the theme change is applied immediately.

## Light and Dark Themes with Custom Fonts

Fonts play a crucial role in UI design. Currently, I use two methods to add custom fonts to my Flutter applications.

**Method 1: Adding Fonts from Asset Files**

Define a `TextStyle` using a custom font stored in the `assets` folder:

```dart
static const _neoTextStyle = TextStyle(
  fontFamily: WebFontFamily.nanumSquareNeo,
  fontFamilyFallback: [
    WebFontFamily.pretendard,
  ],
  package: 'dsg_ui_core', // Loading the font from a package
  height: 1.5,
  leadingDistribution: TextLeadingDistribution.even,
);
```

You can include fonts in your `pubspec.yaml` and reference them in the `TextStyle`. If using fonts from a package, ensure you specify the `package` argument correctly.

#### **Method 2: Using Google Fonts**

If your desired font is available on [Google Fonts](https://pub.dev/packages/google_fonts), you can use it directly with the `google_fonts` package:

```dart
static final _webTextStyle = GoogleFonts.inter().copyWith(
  fontWeight: FontWeight.w600,
  height: 1.5,
  leadingDistribution: TextLeadingDistribution.even,
);
```

#### **Handling Font Scaling for Different Screen Sizes**

When the screen size changes, fonts should scale proportionally to maintain design consistency. One way to achieve this is by defining a **ratio** based on the screen width:

```dart
double get webRatio {
  final width = MediaQuery.of(this).size.width;
  final ratio = width / 1440;
  return ratio < 1 ? (ratio < 0.75 ? 0.75 : ratio) : 1;
}
```

#### **Applying Scaled Font Styles from Figma Design**

Once we have the ratio, we can create text styles dynamically:

```dart
TextStyle get h46B => _webTextStyle.copyWith(
  fontSize: 46 * webRatio,
  fontWeight: FontWeight.w700,
  color: neutral80,
);
```

This approach ensures your fonts scale properly across different devices, keeping your UI responsive and visually consistent.

#### **Method 2: Using the `google_fonts` Library**

You can use the [`google_fonts`](https://pub.dev/packages/google_fonts) package if your desired font is available on Google Fonts.

```dart
static final _webTextStyle = GoogleFonts.inter().copyWith(
  fontWeight: FontWeight.w600,
  height: 1.5,
  leadingDistribution: TextLeadingDistribution.even,
);
```

#### **Handling Font Scaling for Different Screen Sizes**

A common issue when changing screen sizes is that fonts need to scale proportionally to maintain a harmonious design.

In this case, I use a **ratio** based on the screen width. This is calculated by taking the **current screen width** and dividing it by the **original design width** (e.g., 1440px in Figma).

```dart
double get webRatio {
  final width = MediaQuery.of(this).size.width;
  final ratio = width / 1440;
  return ratio < 1 ? (ratio < 0.75 ? 0.75 : ratio) : 1;
}
```

#### **Applying Scaled Font Styles from Figma Design**

Once we have the scaling ratio, we can create text styles dynamically based on the design specifications:

```dart
TextStyle get h46B => _webTextStyle.copyWith(
  fontSize: 46 * webRatio,
  fontWeight: FontWeight.w700,
  color: neutral80,
);
```

#### **Full Code Overview**

```dart
extension WebTextStyle on BuildContext{
/*static const _neoTextStyle = TextStyle(
fontFamily: WebFontFamily.nanumSquareNeo,
fontFamilyFallback: [
WebFontFamily.pretendard,
],
package: 'dsg_ui_core', // Thêm thư viện front chữ từ package: https://api.flutter.dev/flutter/painting/TextStyle-class.html#:~:text=To%20use%20a%20font%20family%20defined%20in%20a%20package%2C%20the%20package%20argument%20must%20be%20provided.%20For%20instance%2C%20suppose%20the%20font%20declaration%20above%20is%20in%20the%20pubspec.yaml%20of%20a%20package%20named%20my_package%20which%20the%20app%20depends%20on.%20Then%20creating%20the%20TextStyle%20is%20done%20as%20follows%3A
height: 1.5,
leadingDistribution:  TextLeadingDistribution.even,

); */
  static final _webTextStyle = GoogleFonts.inter().copyWith(
    fontWeight: FontWeight.w600,
    height: 1.5,
    leadingDistribution: TextLeadingDistribution.even,

  );

  /// Edit ratio of fontSize for responsive screen
  double get webRatio {
    final width = MediaQuery.of(this).size.width;
    final ratio = width / 1440;
    return ratio < 1 ? ratio < 0.75 ? 0.75 : ratio : 1;
  }

  /// Heading

  TextStyle get h46B =>
      _webTextStyle.copyWith(
        fontSize: 46 * webRatio,
        fontWeight: FontWeight.w700,
        color: white,
      );
}
```

#### **Usage Example**

You can apply the text styles as follows:

```dart
Text("Hello", style: context.h46B)
```

#### **Customizing Styles with Colors**

You can fully customize styles according to your design system. Here’s an example of modifying the text color dynamically:

```dart
Text("Hello", style: context.b10B.copyWith(
  color: context.white,
))
```

With this setup, when the **light/dark mode** changes, the text color will automatically adapt based on the selected theme.

This concludes my guide on setting up **light/dark mode in Flutter**. You can explore more about creating a UI package at

{% content-ref url="/pages/nTBlb18opkIcuVJhsaxA" %}
[Core UI](/flutter/ui/core-ui.md)
{% endcontent-ref %}

[Buy Me a Coffee](https://buymeacoffee.com/ducmng12g) | [Support Me on Ko-fi](https://ko-fi.com/I2I81AEJG8)
