Tour
oge-tour walks people through a page — onboarding, a new feature, a changed layout — one card at a time.
Each step dims the page, cuts a spotlight around its target, scrolls it into view and places the card beside it, flipping to fit; a step without a target centers the card. The card is a modal dialog named by its title, with Back, Next / Done and Skip; → and ← move between steps (mirrored in RTL), Escape skips and focus returns where it was. Under prefers-reduced-motion the spotlight jumps instead of gliding and scrolling is instant.
Guided tour
Targets are CSS selectors here (an element or a function works too); placement picks the side of the card, which flips when it does not fit. The last step has no target, so its card is centered. closed reports how it ended — done, skip, escape, backdrop or api — so an app can show a tour only once.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeTour } from '@oge-ui/overlay';
import type { OgeTourClosedEvent, OgeTourStep } from '@oge-ui/overlay';
@Component({
selector: 'demo-root',
imports: [OgeTour],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="toolbar">
<input id="tour-search" type="search" aria-label="Search" />
<button id="tour-filters" type="button">Filters</button>
<button id="tour-export" type="button">Export</button>
</div>
<button type="button" (click)="tour.start()">Take the tour</button>
<oge-tour #tour [steps]="steps" (closed)="onClosed($event)" />
<p>{{ last() }}</p>
`,
})
export class Demo {
protected readonly last = signal('Not taken yet');
protected readonly steps: OgeTourStep[] = [
{
target: '#tour-search',
title: 'Search everything',
content: 'Type a customer, an invoice number or an amount.',
},
{
target: '#tour-filters',
title: 'Narrow it down',
content: 'Filters keep their state when you come back.',
placement: 'bottom-start',
},
{
target: '#tour-export',
title: 'Take the data with you',
content: 'Export the current view to Excel or PDF.',
placement: 'left',
},
// no target: the card is centered
{ title: 'You are all set', content: 'Reopen this tour any time from the Help menu.' },
];
protected onClosed(event: OgeTourClosedEvent): void {
// store it to show the tour only once
this.last.set(`Closed by ${event.reason} on step ${event.step + 1}`);
}
}Resuming & centered steps
[(step)] and [(opened)] are two-way, so a tour can resume where the user left off. Steps without a target center the card over a dimmed page; closeOnBackdropClick lets a press on the page skip the tour (off by default).
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeTour } from '@oge-ui/overlay';
import type { OgeTourStep } from '@oge-ui/overlay';
@Component({
selector: 'demo-root',
imports: [OgeTour],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- [(step)] and [(opened)] are two-way: resume where the user left off. -->
<button type="button" (click)="opened.set(true)">Resume the tour</button>
<oge-tour
[steps]="steps"
[(step)]="step"
[(opened)]="opened"
[closeOnBackdropClick]="true"
/>
<p>Step {{ step() + 1 }} of {{ steps.length }}</p>
`,
})
export class Demo {
protected readonly step = signal(0);
protected readonly opened = signal(false);
protected readonly steps: OgeTourStep[] = [
{ title: 'Welcome to OGE', content: 'A two-minute look at what is new.' },
{ title: 'Faster grids', content: 'Scrolling 100,000 rows now runs at 60 fps.' },
{ title: 'New components', content: 'Image viewer, command palette and this tour.' },
];
}