Signal-based responsive breakpoints for Angular. Inject the service, call a method, get a Signal<boolean> — no RxJS, no subscriptions, no boilerplate.
- Angular 17+
npm install @irv-labs/ngx-responsive-signalsimport { 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 />
}| Screen | Width |
|---|---|
Mobile |
<= 480px |
Tablet |
481 – 768px |
LargeTablet |
769 – 1024px |
Desktop |
1025 – 1280px |
LargeDesktop |
> 1280px |
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);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, LargeDesktopReturns 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, LargeTabletReturns Signal<boolean> — true when the current screen is strictly larger than the given one.
aboveTablet = this.responsive.isLarger(Screen.Tablet); // LargeTablet, Desktop, LargeDesktopReturns Signal<boolean> — true when the current screen is strictly smaller than the given one.
belowDesktop = this.responsive.isSmaller(Screen.Desktop); // Mobile, Tablet, LargeTabletSignal<Screen> — the current screen value. Useful for the pipe or for derived logic.
screen = this.responsive.screen;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() |
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.
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.
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.
| 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 |
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 anycomputedoreffect - Zero setup — works without
provideResponsive(), custom breakpoints are opt-in - SSR-safe — no
windowaccess 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
MIT