ng-beacon
v0.1.0
Published
Lightweight guided-tour library for Angular 19+ with signal-based state, SVG spotlight overlays, keyboard navigation, and i18n support.
Maintainers
Readme
ng-beacon
Lightweight guided-tour library for Angular 19+ with Angular Signals and zoneless-compatible rendering.
SVG spotlight overlays, keyboard navigation, and lightweight i18n hooks with zero runtime dependencies beyond Angular.
Animated demo: View the GitHub README demo or open the GIF directly.
Install
npm install ng-beaconStackblitz Demo
https://stackblitz.com/edit/stackblitz-starters-midtdjmx
Quick Start
// app.config.ts
import { provideBeacon } from 'ng-beacon';
export const appConfig = {
providers: [provideBeacon()],
};<!-- app.component.html -->
@if (beaconService.isActive()) {
<beacon-overlay />
}// Define steps
const TOUR: BeaconStep[] = [
{ id: 'welcome', title: 'Welcome!', content: 'Let me show you around.', position: 'center', showWithoutTarget: true },
{ id: 'nav', title: 'Navigation', content: 'Use the sidebar to navigate.', position: 'end', selector: '[data-tour="sidebar"]' },
];
// Start a tour directly (snapshot — steps are fixed for the tour's lifetime)
this.beaconService.start(TOUR);
// Or start from all registered context steps (reactive — steps from
// destroyed components are automatically pruned from the running tour)
this.beaconService.startContextTour();Component-scoped step registration
Components can register steps that are automatically added to and removed from the context registry:
import { registerTourSteps, BeaconStep } from 'ng-beacon';
const MY_STEPS: BeaconStep[] = [
{ id: 'feature', title: 'New Feature', content: 'Check this out!', position: 'below', selector: '[data-tour="feature"]' },
];
@Component({ /* ... */ })
export class FeatureComponent {
private readonly _tour = registerTourSteps(MY_STEPS); // auto-unregisters on destroy
}When a component with registered steps is destroyed during an active context tour, those steps are automatically removed from the running tour and the step index adjusts accordingly.
If UI changes cause previously hidden elements to appear (or visible ones to disappear), call beaconService.recalculate() to rebuild the active context tour. The current step is preserved by id.
If your app uses Angular Router and you want tours to close after route changes, subscribe to NavigationEnd and call beaconService.stop() from app-level code.
See the full documentation for i18n, theming, component-scoped registration, and API reference.
Keyboard support includes Escape to close, ArrowLeft to go back, and ArrowRight to advance.
Events
BeaconService exposes two signals for tracking tour lifecycle:
finished— emits when the user completes all steps (clicks next on the last step)dismissed— emits when the tour is closed early (close button,Escape, click outside, or programmaticstop())
Both are Signal<BeaconTourEvent | null>, starting as null. Each emission is a new object, so effect() fires every time.
interface BeaconTourEvent {
step: BeaconStep; // the step that was active when the event fired
stepIndex: number; // zero-based index
totalSteps: number; // total steps in the tour
}Usage
import { effect, inject } from '@angular/core';
import { BeaconService } from 'ng-beacon';
export class AppComponent {
private readonly beaconService = inject(BeaconService);
constructor() {
effect(() => {
const event = this.beaconService.finished();
if (event) {
localStorage.setItem('tour-completed', 'true');
}
});
effect(() => {
const event = this.beaconService.dismissed();
if (event) {
console.log(`Tour dismissed at step ${event.stepIndex + 1}/${event.totalSteps}`);
}
});
}
}