BrowserStateService: A Single Point of Truth for Dark Mode State in Angular
Tags: anglar, darkmode, chatgpt
Published: 2023-03-17 07:15:00

---
title: BrowserStateService: A Single Point of Truth for Dark Mode State in Angular
published: true
description: This blog post is written by ChatGPT describing how to create a service in Angular which will reflect the dark-mode state in an app
tags: Anglar, darkmode, ChatGPT
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mugjp45mpukwzpdef353.png
# Use a ratio of 100:42 for best results.
published_at: 2023-03-17 07:15 +0000
---

> As more and more users prefer dark mode on their devices, web developers have to keep up with this trend by providing dark mode support on their web applications. This can be achieved in several ways, but maintaining the state of dark mode across the application can be a daunting task, especially as it grows larger. A good solution is to use a single point of truth in a service that maintains the state of dark mode across all components. This is where the BrowserStateService comes in.


## TLDR
* The BrowserStateService is an Angular service that maintains the state of dark mode across an Angular application.
* It listens for changes to the dark class on the body element, and provides an observable that components can subscribe to in order to observe changes to the state of dark mode.
* The service provides methods for toggling the mode and setting it to a specific value.
* It listens for changes to the user's preferred color scheme at the operating system level, and sets the initial mode accordingly.
* Using this service can help maintain a single point of truth for the state of dark mode across an Angular application.

## The code

`browserstate.service.ts` looks like this:

```Typescript
import { BehaviorSubject } from 'rxjs';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class BrowserStateService {
  private isDarkModeSubject = new BehaviorSubject<boolean>(false);
  public isDarkMode$ = this.isDarkModeSubject.asObservable();

  constructor() {
    // Check if 'dark' class is present on body element on initialization
    this.isDarkModeSubject.next(document.body.classList.contains('dark'));

    // Watch for changes to 'dark' class on body element
    new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.attributeName === 'class') {
          const isDark = document.body.classList.contains('dark');
          this.isDarkModeSubject.next(isDark);
        }
      });
    }).observe(document.body, { attributes: true });

    // Listen for user's preferred color scheme
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    mediaQuery.addEventListener('change', (event) => {
      const isDark = event.matches;
      this.setDarkMode(isDark);
    });

    // Set initial mode based on user's preferred color scheme
    if (mediaQuery.matches) {
      this.setDarkMode(true);
    }
  }

  toggleMode() {
    const isDark = !this.isDarkModeSubject.value;
    this.setDarkMode(isDark);
  }

  setDarkMode(isDark: boolean) {
    if (isDark) {
      document.body.classList.add('dark');
    } else {
      document.body.classList.remove('dark');
    }

    this.isDarkModeSubject.next(isDark);
  }
}
``` 

## How to use
To use the BrowserStateService in your Angular application, follow these steps:

1) Create a new file named `browser-state.service.ts` in your Angular project's `src/app` directory.

2) Copy the code from the example in the previous section and paste it into the `browser-state.service.ts` file.

3) Import the service in any component where you want to observe or change the state of dark mode:

```
import { BrowserStateService } from './browser-state.service';
```

4) Inject the service in the component's constructor:
```
constructor(private browserStateService: BrowserStateService) {}
```
You can also import it as `public` if you for instance want to use it in you template like this: `{{ browserStateService.isDarkKode$ || async }}`.

5) Use the `isDarkMode$` observable to observe changes to the state of dark mode, and the `setDarkMode()` and `toggleMode()` methods to change the state of dark mode:

``` 
// Subscribe to changes to the state of dark mode
this.browserStateService.isDarkMode$.subscribe(isDarkMode => {
  // Do something based on the value of isDarkMode
});

// Set the state of dark mode
this.browserStateService.setDarkMode(true);

// Toggle the state of dark mode
this.browserStateService.toggleMode();
```

## Example of Use
Here's an example of how you can use the BrowserStateService in an Angular component:
```
import { Component, OnInit } from "@angular/core";
import { BrowserStateService } from "./browser-state.service";

@Component({
  selector: "app-my-component",
  template: `
    <div [ngClass]="{ 'dark-mode': isDarkMode }">
      <p>Some text in the component.</p>
      <button (click)="toggleMode()">Toggle Mode</button>
    </div>
  `,
})
export class MyComponent implements OnInit {
  isDarkMode: boolean;

  constructor(private browserStateService: BrowserStateService) {}

  ngOnInit() {
    // Subscribe to changes to the
    // state of dark mode
    this.browserStateService.isDarkMode$.subscribe((isDarkMode) => {
      this.isDarkMode = isDarkMode;
    });
  }

  toggleMode() {
    this.browserStateService.toggleMode();
  }
}

```

In this example, we're using the `ngClass` directive to conditionally apply the `dark-mode` class to the `div` element based on the value of the `isDarkMode` property. We're also using a button to call the `toggleMode()` method of the `BrowserStateService` to toggle the state of dark mode.

## Conclusion

The `BrowserStateService` is a simple and effective way to maintain the state of dark mode across an Angular application. By using a single point of truth in a service, you can avoid the complexity of managing the state of dark mode across multiple components, and provide a more consistent user experience. The `BrowserStateService` listens for changes to the `dark` class on the `body` element, and provides methods for toggling the mode and setting it to a specific value. Additionally, it listens for changes to the user's preferred color scheme at the operating system level, and sets the initial mode accordingly.

Thank you to ChatGPT for providing the code for this useful Angular service.