A simple service for responsive Angular applications
Building responsive user interfaces can sometimes feel like a puzzle. Angular's BreakpointObserver from the CDK is a fantastic tool for reacting to screen size changes, and when combined with the power of signals, it becomes even more elegant. Let's look at a simple service that centralizes your responsive logic, making your components cleaner and more declarative.
What this service does
This ResponsiveManager service simplifies how you react to different screen sizes across your Angular application:
- Observes Breakpoints: It uses the Angular CDK's
BreakpointObserverto detect when predefined screen widths are met. In our example, it checks for screens(max-width: 600px). - Signals for Reactivity: The magic happens when we use
toSignalto convert theBreakpointObserver's observable stream into a reactive signal (screenWidth). - Derived Screen State: From
screenWidth, we createcomputedsignals likesmallWidth. ThissmallWidthsignal will automatically update totrueorfalsebased on whether the current screen falls within our "small" breakpoint. - Application-Specific Logic: You can then build further
computedsignals, such assideNavMode, which dynamically changes the mode of a Material side navigation (e.g., 'side' for larger screens, 'over' for small screens).
Here's the code:
@Injectable({
providedIn: "root",
})
export class ResponsiveManager {
// Add other widths as needed
private readonly small = "(max-width: 600px)";
// Observe widths and convert to a signal
private readonly screenWidth = toSignal(
inject(BreakpointObserver).observe([this.small]),
);
// Create computeds for easy component binding
public readonly smallWidth = computed(
() => this.screenWidth()?.breakpoints[this.small],
);
// Example: More derived signals for components
private readonly sideNavOpened = signal(true); // Manages open state
public readonly sideNavMode = computed(() =>
!this.smallWidth() ? "side" : "over",
); // Changes mode based on width
toggleSideNav() {
this.sideNavOpened.set(!this.sideNavOpened());
}
}
Why it's useful
This approach offers several benefits for your Angular development:
- Clean Components: Components don't need to directly subscribe to
BreakpointObserveror manage complex RxJS streams. They simply consume signals. - Declarative UI: You can bind directly to
computedsignals in your templates, making your UI logic more readable and declarative. For example,[mode]="responsiveManager.sideNavMode()"is very straightforward. - Centralized Logic: All your breakpoint definitions and core responsive logic reside in one service, making it easier to maintain and extend.
- Performance: Signals provide fine-grained reactivity, potentially leading to more efficient change detection updates only for parts of your UI that actually depend on the changing signal values.
How to use it
Using the ResponsiveManager in your components is straightforward:
-
Inject the service:
import { Component, inject } from "@angular/core"; import { ResponsiveManager } from "./responsive-manager.service"; // Adjust path @Component({ // ... }) export class MyResponsiveComponent { readonly responsiveManager = inject(ResponsiveManager); // Access signals directly in template or in component logic // e.g., this.responsiveManager.smallWidth() } -
Bind in your template: You can then bind the
computedsignals directly to your HTML elements or component inputs. For instance, if you're using Angular Material'smat-sidenav:<mat-sidenav-container> <mat-sidenav [mode]="responsiveManager.sideNavMode()" [opened]="responsiveManager.sideNavOpened()" > <!-- Sidenav content --> </mat-sidenav> <mat-sidenav-content> <!-- Main content --> </mat-sidenav-content> </mat-sidenav-container> -
Extend it: Easily add more breakpoints (
medium,large, etc.) and correspondingcomputedsignals in theResponsiveManagerservice to cover all your responsive needs.
By using this pattern, you can build responsive Angular applications with a clean, signal-driven approach that is both powerful and easy to understand.
This responsive manager was part of my Modern Angular Ecommerce App. You can find the full code and a list of all features here: Code Link
