A framework-agnostic, vanilla-TypeScript user-onboarding tour library. Renders guided product tours / onboarding walkthroughs with step-by-step dialogs, backdrop highlights, and collision-aware positioning.
npm install senangwebs-zeroimport { SenangWebsZero } from 'senangwebs-zero';
import 'senangwebs-zero/dist/swz.css';
const tour = new SenangWebsZero({ /* options */ });
tour.start(); // ungrouped steps
tour.start('nav'); // steps with data-swz-group="nav"<link rel="stylesheet" href="https://unpkg.com/senangwebs-zero/dist/swz.css">
<script src="https://unpkg.com/senangwebs-zero/dist/swz.umd.js"></script>
<script>
const tour = new swz.SenangWebsZero({ /* options */ });
tour.start();
</script>Add data-swz-tour to any element. The element becomes the highlight target.
Step content is rendered as HTML, so only pass trusted or sanitized content.
<div data-swz-tour="Welcome to the dashboard!" data-swz-title="Step 1">Dashboard</div>
<button data-swz-tour="Click here to save" data-swz-group="editor">Save</button>| Attribute | Description |
|---|---|
data-swz-tour |
Required. Step content (HTML allowed). |
data-swz-title |
Title shown in dialog header. |
data-swz-group |
Group key; step only runs with start("group"). |
data-swz-order |
Sort order (ascending). |
data-swz-fixed |
Treat target as position:fixed for highlight positioning. |
data-swz-margin |
Per-step scroll margin override (px). |
data-swz-placement |
Per-step dialog placement: auto, top, right, bottom, or left. |
const tour = new SenangWebsZero({
steps: [
{ content: 'Welcome!', title: 'Intro', target: '#header', order: 1 },
{ content: 'Click save to continue.', target: '#save-btn', placement: 'right', order: 2 },
{ content: 'Centered step with no target.', title: 'Done', order: 3 },
],
});
tour.start();Object steps support content, title, target, order, group, margin, fixed, and placement.
Use placement: 'auto' to let SWZ pick the best side for that step, or set top, right, bottom, or left to prefer a side while still allowing viewport-safe fallback.
new SenangWebsZero(options?: SWZOptions)Does not auto-start.
| Method | Description |
|---|---|
start(group?) |
Begin the tour. With group, only steps matching that group run. |
visitStep('next' | 'prev' | number) |
Navigate to next, previous, or specific step index. |
nextStep() |
Advance one step (or finish if last). |
prevStep() |
Go back one step. |
exit() |
Close the tour without recording completion. Fires onBeforeExit/onAfterExit. |
finishTour(exit?, group?) |
Programmatically mark complete. If exit is true (default), also closes the tour. |
isFinished(group?) |
boolean — whether the tour group was completed. |
deleteFinishedTour(group?) |
Clear the completion record. |
addSteps(steps[]) |
Append object steps to the tour. |
setOptions(options) |
Shallow-merge options at runtime. |
refresh() |
Recompute steps (rescan DOM + object steps), re-render. |
refreshDialog() |
Re-render dialog content/position only (no step recompute). |
updatePositions() |
Recompute backdrop + dialog geometry only. |
| Property | Type | Description |
|---|---|---|
isVisible |
boolean |
true while the tour is on screen. |
activeStep |
number |
Zero-based current step index. Writable; pair with refreshDialog(). |
tourSteps |
SWZStep[] |
Resolved, ordered step list. Mutable. |
dialog |
HTMLElement |
Dialog DOM node. |
backdrop |
HTMLElement |
Backdrop DOM node. |
options |
SWZOptions |
Active resolved options. |
group |
string | undefined |
Active group if start(group) was used. |
Single-handler, last-registration-wins. Each handler may be sync or return a Promise. Rejecting (or resolving false) cancels the gated action.
| Hook | Fires | Gating |
|---|---|---|
onBeforeStepChange(fn) |
Before step transition | reject → cancel change |
onAfterStepChange(fn) |
After new step renders | no |
onBeforeExit(fn) |
Before exit (escape, click‑outside, close btn) | reject → stay open |
onAfterExit(fn) |
After teardown | no |
onFinish(fn) |
Finish button on last step | reject → cancel finish |
tour.onBeforeStepChange(() => {
if (!canProceed) throw new Error('Blocked'); // cancels navigation
});
tour.onFinish(async () => {
await api.markOnboardingComplete();
});| Option | Type | Default | Description |
|---|---|---|---|
steps |
SWZStep[] |
[] |
Steps declared as objects at construction. |
autoScroll |
boolean |
true |
Scroll window so target is in view. |
autoScrollSmooth |
boolean |
true |
Use smooth scrolling. |
autoScrollOffset |
number |
20 |
Margin (px) around target when scrolling. |
backdropColor |
string |
'rgba(20,20,21,0.84)' |
Overlay color (any valid CSS). |
backdropClass |
string |
'' |
Extra CSS class on backdrop element. |
backdropAnimate |
boolean |
true |
Animate cutout position between steps. |
targetPadding |
number |
30 |
Padding (px) of the highlight cut‑out. |
dialogClass |
string |
'' |
Extra CSS class on dialog element. |
dialogZ |
number |
999 |
z-index of the dialog. |
dialogWidth |
number |
0 |
Fixed dialog width (px). 0 = auto. |
dialogMaxWidth |
number |
340 |
Max dialog width (px). |
dialogPlacement |
'auto'|'top'|'right'|'bottom'|'left' |
undefined |
Preferred side. auto or undefined lets SWZ choose. |
dialogAnimate |
boolean |
true |
Animate dialog position between steps. |
closeButton |
boolean |
true |
Show close (✕) button. |
nextLabel |
string |
'Next' |
Next button text. |
prevLabel |
string |
'Back' |
Back button text. |
finishLabel |
string |
'Finish' |
Final-step button text. |
hideNext |
boolean |
false |
Hide next button. |
hidePrev |
boolean |
false |
Hide back button. |
showButtons |
boolean |
true |
Master toggle for nav buttons. |
showStepDots |
boolean |
true |
Show progress dots. |
stepDotsPlacement |
'footer'|'body' |
'footer' |
Where dots render. |
showStepProgress |
boolean |
true |
Show n/total progress text. |
progressBar |
string |
'' |
Color string → renders progress bar. |
completeOnFinish |
boolean |
true |
Persist completion in localStorage. |
rememberStep |
boolean |
false |
Resume from last active step on reopen. |
exitOnEscape |
boolean |
true |
Escape key exits the tour. |
exitOnClickOutside |
boolean |
true |
Click outside dialog exits. |
keyboardControls |
boolean |
true |
Arrow keys navigate, Escape exits. |
propagateEvents |
boolean |
false |
Allow interaction with target through highlight. |
debug |
boolean |
true |
Emit console diagnostics. |
Completion is tracked in localStorage using swz:-prefixed keys keyed by group (default group = "tour").
tour.onFinish(() => console.log('done'));
tour.start('onboarding');
tour.isFinished('onboarding'); // true after finishing
tour.deleteFinishedTour('onboarding'); // resetWith rememberStep: true, the last active step is also stored and resumed on next start().
All DOM elements use the .swz-* namespace:
.swz-backdrop — full-viewport overlay
.swz-cutout — highlight hole (child of backdrop)
.swz-dialog — floating popover
.swz-dialog-header
.swz-dialog-title
.swz-dialog-close
.swz-progressbar — colored bar under header
.swz-dialog-body
.swz-dots — step indicator dots
.swz-dialog-footer
.swz-prev — back button
.swz-progress — "n/total" text
.swz-next — next/finish button
.swz-arrow — caret pointing at target
Pass dialogClass / backdropClass for custom styling hooks.
- Dialog has
role="dialog",aria-modal, andaria-labelfrom step title. - Focus moves to dialog on each step; focus returns to trigger element on exit.
- Tab is trapped within the dialog while open.
- All buttons are real
<button>s with accessible names. prefers-reduced-motion: reducedisables all animations and smooth scrolling.
Full type definitions ship with the package:
import type { SWZOptions, SWZPlacement, SWZStep } from 'senangwebs-zero';npm run build # JS (rollup) + CSS (sass)
npm run build:js # rollup only
npm run build:css # sass only
npm run lint # tsc --noEmitOutputs:
| File | Format |
|---|---|
dist/swz.esm.mjs |
ES Module |
dist/swz.cjs.js |
CommonJS |
dist/swz.umd.js |
UMD (CDN global swz) |
dist/swz.css |
Compiled CSS |
dist/types/ |
.d.ts declarations |
MIT