Sitelet https://github.com/irvrodflo/ngx-responsive-signals
Skip to content

Repository files navigation

ngx-responsive-signals

Signal-based responsive breakpoints for Angular. Inject the service, call a method, get a Signal<boolean> — no RxJS, no subscriptions, no boilerplate.


Requirements

  • Angular 17+

Installation

npm install @irv-labs/ngx-responsive-signals

Quick Start

import { ResponsiveService, Screen } from '@irv-labs/ngx-responsive-signals';

@Component({ ... })
export class MyComponent {
  private responsive = inject(ResponsiveService);

  isMobile    = this.responsive.is(Screen.Mobile);
  showSidebar = this.responsive.isAtLeast(Screen.Tablet);
  isCompact   = this.responsive.isAtMost(Screen.Tablet);
}
@if (isMobile()) {
<app-mobile-nav />
} @else {
<app-desktop-nav />
}

Breakpoints

Screen Width
Mobile <= 480px
Tablet 481 – 768px
LargeTablet 769 – 1024px
Desktop 1025 – 1280px
LargeDesktop > 1280px

API

responsive.is(screen)

Returns Signal<boolean> — true only when the current screen matches exactly.

isMobile = this.responsive.is(Screen.Mobile);
isTablet = this.responsive.is(Screen.Tablet);
isDesktop = this.responsive.is(Screen.Desktop);

responsive.isAtLeast(screen)

Returns Signal<boolean> — true when the current screen is that size or larger.

showSidebar = this.responsive.isAtLeast(Screen.Tablet); // Tablet, LargeTablet, Desktop, LargeDesktop
fullLayout = this.responsive.isAtLeast(Screen.Desktop); // Desktop, LargeDesktop

responsive.isAtMost(screen)

Returns Signal<boolean> — true when the current screen is that size or smaller.

isCompact = this.responsive.isAtMost(Screen.Tablet); // Mobile, Tablet
stackedNav = this.responsive.isAtMost(Screen.LargeTablet); // Mobile, Tablet, LargeTablet

responsive.isLarger(screen)

Returns Signal<boolean> — true when the current screen is strictly larger than the given one.

aboveTablet = this.responsive.isLarger(Screen.Tablet); // LargeTablet, Desktop, LargeDesktop

responsive.isSmaller(screen)

Returns Signal<boolean> — true when the current screen is strictly smaller than the given one.

belowDesktop = this.responsive.isSmaller(Screen.Desktop); // Mobile, Tablet, LargeTablet

responsive.screen

Signal<Screen> — the current screen value. Useful for the pipe or for derived logic.

screen = this.responsive.screen;

Pipe

Import ResponsivePipe in your component and pass responsive.screen as input. The argument follows the format 'screen' or 'screen:modifier'.

imports: [ResponsivePipe];
screen = inject(ResponsiveService).screen;
<!-- Exact -->
@if (screen() | responsive:'mobile') { }

<!-- isAtLeast -->
@if (screen() | responsive:'tablet:least') { }

<!-- isAtMost -->
@if (screen() | responsive:'desktop:most') { }

<!-- isLarger -->
@if (screen() | responsive:'tablet:larger') { }

<!-- isSmaller -->
@if (screen() | responsive:'tablet:smaller') { }
Modifier Equivalent service method
(none) is()
:least isAtLeast()
:most isAtMost()
:larger isLarger()
:smaller isSmaller()

Custom Breakpoints

Call provideResponsive() in app.config.ts to override the default values. Only pass what you need — the rest keeps its default.

// app.config.ts
import { provideResponsive } from '@irv-labs/ngx-responsive-signals';

export const appConfig: ApplicationConfig = {
  providers: [
    provideResponsive({
      mobile: 640,
      desktop: 1440,
      // tablet and largeTablet stay at their defaults
    }),
  ],
};

Calling provideResponsive() is optional — the service works with the default breakpoints out of the box.


SSR

The service is SSR-safe. On the server, window is never accessed — the screen defaults to Mobile (width 0), which is the most conservative fallback for layout decisions.


Path Alias (optional)

If you prefer a shorter import, add a path alias in your tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "@responsive": ["./node_modules/@irv-labs/ngx-responsive-signals"]
    }
  }
}
// Before
import { ResponsiveService, Screen } from '@irv-labs/ngx-responsive-signals';

// After
import { ResponsiveService, Screen } from '@responsive';

This is a local convenience — it does not affect the published package or teammates unless they add the same alias.


Public API

Export Description
ResponsiveService Core service — is, isAtLeast, isAtMost, isLarger, isSmaller
ResponsivePipe Pipe that resolves a screen + modifier to boolean
provideResponsive Registers custom breakpoints in app.config
Screen Enum — Mobile, Tablet, LargeTablet, Desktop, LargeDesktop
SCREEN_ORDER Ordinal map used internally for comparisons
RESPONSIVE_BREAKPOINTS InjectionToken for the breakpoints config
DEFAULT_BREAKPOINTS Default breakpoint values
ResponsiveBreakpoints Config interface for provideResponsive
ResponsiveModifier 'least' | 'most' | 'larger' | 'smaller'
ResponsivePipeArg Union type for all valid pipe arguments

Philosophy

Angular Signals make reactive state simple — a boolean that updates when the window resizes should be nothing more than a computed. This library takes that idea to its logical conclusion: one service, a handful of methods, all returning signals. No Observables to subscribe to, no async pipes, no manual cleanup.

The comparison model is built on a single ordinal map — each screen maps to a number, and isAtLeast, isAtMost, isLarger, isSmaller become single-line comparisons. The result is predictable, testable, and easy to reason about.

  • Signal-native — every method returns Signal<boolean>, composable with any computed or effect
  • Zero setup — works without provideResponsive(), custom breakpoints are opt-in
  • SSR-safe — no window access on the server
  • No memory leaks — the resize listener is cleaned up via DestroyRef
  • Dev-time safety — breakpoint order is validated at startup, not silently ignored

License

MIT

About

Signal-based responsive breakpoints for Angular

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages