0
# Event Handling
1
2
Rich callback system for handling tour and hint lifecycle events, enabling custom behavior and integration with analytics or other systems.
3
4
## Capabilities
5
6
### Tour Event Callbacks
7
8
Comprehensive event system for Tour instances with lifecycle hooks and interaction events.
9
10
```typescript { .api }
11
/**
12
* Callback fired before changing to a new step
13
* Return false to prevent the step change
14
*/
15
type introBeforeChangeCallback = (
16
this: Tour,
17
targetElement: HTMLElement,
18
currentStep: number,
19
direction: "backward" | "forward"
20
) => Promise<boolean> | boolean;
21
22
/**
23
* Callback fired when changing to a new step
24
*/
25
type introChangeCallback = (
26
this: Tour,
27
targetElement: HTMLElement
28
) => void | Promise<void>;
29
30
/**
31
* Callback fired after changing to a new step
32
*/
33
type introAfterChangeCallback = (
34
this: Tour,
35
targetElement: HTMLElement
36
) => void | Promise<void>;
37
38
/**
39
* Callback fired when tour is completed
40
*/
41
type introCompleteCallback = (
42
this: Tour,
43
currentStep: number,
44
reason: "skip" | "end" | "done"
45
) => void | Promise<void>;
46
47
/**
48
* Callback fired when tour is started
49
*/
50
type introStartCallback = (
51
this: Tour,
52
targetElement: HTMLElement
53
) => void | Promise<void>;
54
55
/**
56
* Callback fired when tour is exited
57
*/
58
type introExitCallback = (
59
this: Tour
60
) => void | Promise<void>;
61
62
/**
63
* Callback fired when tour is skipped
64
*/
65
type introSkipCallback = (
66
this: Tour,
67
currentStep: number
68
) => void | Promise<void>;
69
70
/**
71
* Callback fired before tour exit
72
* Return false to prevent the exit
73
*/
74
type introBeforeExitCallback = (
75
this: Tour,
76
targetElement: HTMLElement
77
) => boolean | Promise<boolean>;
78
```
79
80
### Tour Callback Registration
81
82
Methods for registering event callbacks on Tour instances.
83
84
```typescript { .api }
85
/**
86
* Set callback for before step change event
87
* @param callback - Function to call before changing steps
88
*/
89
onBeforeChange(callback: introBeforeChangeCallback): Tour;
90
91
/**
92
* Set callback for step change event
93
* @param callback - Function to call when changing steps
94
*/
95
onChange(callback: introChangeCallback): Tour;
96
97
/**
98
* Set callback for after step change event
99
* @param callback - Function to call after changing steps
100
*/
101
onAfterChange(callback: introAfterChangeCallback): Tour;
102
103
/**
104
* Set callback for tour completion event
105
* @param callback - Function to call when tour completes
106
*/
107
onComplete(callback: introCompleteCallback): Tour;
108
109
/**
110
* Set callback for tour start event
111
* @param callback - Function to call when tour starts
112
*/
113
onStart(callback: introStartCallback): Tour;
114
115
/**
116
* Set callback for tour exit event
117
* @param callback - Function to call when tour exits
118
*/
119
onExit(callback: introExitCallback): Tour;
120
121
/**
122
* Set callback for tour skip event
123
* @param callback - Function to call when tour is skipped
124
*/
125
onSkip(callback: introSkipCallback): Tour;
126
127
/**
128
* Set callback for before tour exit event
129
* @param callback - Function to call before tour exits
130
*/
131
onBeforeExit(callback: introBeforeExitCallback): Tour;
132
133
/**
134
* Get a specific callback function
135
* @param callbackName - Name of the callback to retrieve
136
*/
137
callback<K extends keyof TourCallbacks>(callbackName: K): TourCallbacks[K] | undefined;
138
139
interface TourCallbacks {
140
onBeforeChange?: introBeforeChangeCallback;
141
onChange?: introChangeCallback;
142
onAfterChange?: introAfterChangeCallback;
143
onComplete?: introCompleteCallback;
144
onStart?: introStartCallback;
145
onExit?: introExitCallback;
146
onSkip?: introSkipCallback;
147
onBeforeExit?: introBeforeExitCallback;
148
}
149
```
150
151
### Tour Event Usage Examples
152
153
**Basic Event Handling:**
154
155
```javascript
156
import introJs from "intro.js";
157
158
const tour = introJs.tour()
159
.addSteps([
160
{ title: "Welcome", intro: "Welcome to our app!", element: "#welcome" },
161
{ title: "Features", intro: "Check out these features", element: "#features" },
162
{ title: "Settings", intro: "Configure your preferences", element: "#settings" }
163
]);
164
165
// Track tour start
166
tour.onStart(function(targetElement) {
167
console.log("Tour started on:", targetElement);
168
169
// Analytics tracking
170
gtag('event', 'tour_started', {
171
'event_category': 'onboarding',
172
'event_label': 'product_tour'
173
});
174
});
175
176
// Track step changes
177
tour.onChange(function(targetElement) {
178
const currentStep = this.getCurrentStep();
179
console.log(`Moved to step ${currentStep + 1}`);
180
181
// Track step engagement
182
gtag('event', 'tour_step_viewed', {
183
'event_category': 'onboarding',
184
'step_number': currentStep + 1
185
});
186
});
187
188
// Handle tour completion
189
tour.onComplete(function(currentStep, reason) {
190
console.log(`Tour completed. Reason: ${reason}`);
191
192
// Track completion
193
gtag('event', 'tour_completed', {
194
'event_category': 'onboarding',
195
'completion_reason': reason,
196
'steps_completed': currentStep + 1
197
});
198
199
// Show success message
200
if (reason === "done") {
201
showSuccessMessage("Great! You've completed the tour.");
202
}
203
});
204
205
await tour.start();
206
```
207
208
**Advanced Event Handling with Conditional Logic:**
209
210
```javascript
211
import introJs from "intro.js";
212
213
const tour = introJs.tour();
214
215
// Conditional step progression
216
tour.onBeforeChange(function(targetElement, currentStep, direction) {
217
console.log(`About to ${direction} from step ${currentStep}`);
218
219
// Validate user action before proceeding
220
if (currentStep === 1 && direction === "forward") {
221
const isFormValid = validateRequiredForm();
222
if (!isFormValid) {
223
alert("Please complete the required form before continuing.");
224
return false; // Prevent step change
225
}
226
}
227
228
// Allow step change
229
return true;
230
});
231
232
// Custom step-specific behavior
233
tour.onAfterChange(function(targetElement) {
234
const currentStep = this.getCurrentStep();
235
const stepData = this.getStep(currentStep);
236
237
// Execute step-specific actions
238
switch (currentStep) {
239
case 0:
240
// First step: highlight important UI elements
241
highlightElement("#main-navigation");
242
break;
243
case 1:
244
// Second step: load dynamic content
245
loadUserDashboardData();
246
break;
247
case 2:
248
// Third step: enable interactive features
249
enableDemoMode();
250
break;
251
}
252
});
253
254
// Prevent exit unless confirmed
255
tour.onBeforeExit(function(targetElement) {
256
if (this.getCurrentStep() !== undefined && this.getCurrentStep() < this.getSteps().length - 1) {
257
return confirm("Are you sure you want to exit the tour?");
258
}
259
return true;
260
});
261
```
262
263
### Hint Event Callbacks
264
265
Event system for Hint instances with lifecycle and interaction events.
266
267
```typescript { .api }
268
/**
269
* Callback fired when hints are added to the page
270
*/
271
type hintsAddedCallback = (
272
this: Hint
273
) => void | Promise<void>;
274
275
/**
276
* Callback fired when a hint is clicked
277
*/
278
type hintClickCallback = (
279
this: Hint,
280
item: HintItem
281
) => void | Promise<void>;
282
283
/**
284
* Callback fired when a hint is closed
285
*/
286
type hintCloseCallback = (
287
this: Hint,
288
item: HintItem
289
) => void | Promise<void>;
290
```
291
292
### Hint Callback Registration
293
294
Methods for registering event callbacks on Hint instances.
295
296
```typescript { .api }
297
/**
298
* Set callback for when hints are added to the page
299
* @param callback - Function to call when hints are rendered
300
*/
301
onHintsAdded(callback: hintsAddedCallback): Hint;
302
303
/**
304
* Set callback for hint click events
305
* @param callback - Function to call when hint is clicked
306
*/
307
onHintClick(callback: hintClickCallback): Hint;
308
309
/**
310
* Set callback for hint close events
311
* @param callback - Function to call when hint is closed
312
*/
313
onHintClose(callback: hintCloseCallback): Hint;
314
315
/**
316
* Get a specific callback function
317
* @param callbackName - Name of the callback to retrieve
318
*/
319
callback<K extends keyof HintCallbacks>(callbackName: K): HintCallbacks[K] | undefined;
320
321
interface HintCallbacks {
322
onHintsAdded?: hintsAddedCallback;
323
onHintClick?: hintClickCallback;
324
onHintClose?: hintCloseCallback;
325
}
326
```
327
328
### Hint Event Usage Examples
329
330
**Basic Hint Event Handling:**
331
332
```javascript
333
import introJs from "intro.js";
334
335
const hint = introJs.hint()
336
.addHint({
337
element: "#help-button",
338
hint: "Click for help and support",
339
hintPosition: "top-middle"
340
})
341
.addHint({
342
element: "#settings-gear",
343
hint: "Access your account settings",
344
hintPosition: "bottom-left"
345
});
346
347
// Track when hints are rendered
348
hint.onHintsAdded(function() {
349
console.log("All hints have been added to the page");
350
351
// Analytics tracking
352
gtag('event', 'hints_displayed', {
353
'event_category': 'help_system',
354
'hint_count': this.getHints().length
355
});
356
});
357
358
// Track hint interactions
359
hint.onHintClick(function(item) {
360
console.log("Hint clicked:", item);
361
362
// Track which hints are most useful
363
gtag('event', 'hint_clicked', {
364
'event_category': 'help_system',
365
'hint_element': item.element?.id || 'unknown',
366
'hint_content': item.hint
367
});
368
369
// Show detailed help if needed
370
if (item.hint?.includes("settings")) {
371
showSettingsHelp();
372
}
373
});
374
375
// Track hint dismissals
376
hint.onHintClose(function(item) {
377
console.log("Hint closed:", item);
378
379
gtag('event', 'hint_closed', {
380
'event_category': 'help_system',
381
'hint_element': item.element?.id || 'unknown'
382
});
383
});
384
385
await hint.render();
386
```
387
388
**Advanced Hint Event Handling:**
389
390
```javascript
391
import introJs from "intro.js";
392
393
const hint = introJs.hint();
394
395
// Dynamic hint content based on user context
396
hint.onHintClick(async function(item) {
397
const element = item.element;
398
if (!element) return;
399
400
// Get contextual information
401
const userRole = getUserRole();
402
const featureAccess = await checkFeatureAccess(element.id);
403
404
// Customize hint behavior based on context
405
if (!featureAccess) {
406
showUpgradePrompt();
407
return;
408
}
409
410
// Show role-specific guidance
411
const roleSpecificHint = getHintForRole(item.hint, userRole);
412
if (roleSpecificHint !== item.hint) {
413
// Update hint content dynamically
414
item.hint = roleSpecificHint;
415
this.refresh(); // Refresh to show updated content
416
}
417
418
// Track contextual usage
419
gtag('event', 'contextual_hint_used', {
420
'user_role': userRole,
421
'feature_id': element.id,
422
'has_access': featureAccess
423
});
424
});
425
426
// Auto-close hints after user interaction
427
hint.onHintClick(function(item) {
428
// Close hint after 3 seconds
429
setTimeout(() => {
430
this.hideHintDialog();
431
}, 3000);
432
});
433
```
434
435
### Event Integration Patterns
436
437
**Analytics Integration:**
438
439
```javascript
440
import introJs from "intro.js";
441
442
// Comprehensive analytics tracking
443
function setupTourAnalytics(tour) {
444
const startTime = Date.now();
445
let stepTimes = [];
446
447
tour.onStart(function() {
448
gtag('event', 'tour_started', {
449
'event_category': 'onboarding',
450
'timestamp': startTime
451
});
452
});
453
454
tour.onChange(function() {
455
stepTimes.push(Date.now());
456
});
457
458
tour.onComplete(function(currentStep, reason) {
459
const totalTime = Date.now() - startTime;
460
const avgStepTime = stepTimes.length > 0 ?
461
stepTimes.reduce((a, b, i) => a + (i > 0 ? b - stepTimes[i-1] : 0), 0) / stepTimes.length : 0;
462
463
gtag('event', 'tour_completed', {
464
'event_category': 'onboarding',
465
'completion_reason': reason,
466
'total_time_ms': totalTime,
467
'avg_step_time_ms': avgStepTime,
468
'steps_completed': currentStep + 1
469
});
470
});
471
472
return tour;
473
}
474
475
// Usage
476
const tour = setupTourAnalytics(introJs.tour());
477
```
478
479
**State Management Integration:**
480
481
```javascript
482
import introJs from "intro.js";
483
484
// Redux/state management integration
485
function connectTourToStore(tour, store) {
486
tour.onStart(function() {
487
store.dispatch({ type: 'TOUR_STARTED' });
488
});
489
490
tour.onChange(function() {
491
const currentStep = this.getCurrentStep();
492
store.dispatch({
493
type: 'TOUR_STEP_CHANGED',
494
payload: { step: currentStep }
495
});
496
});
497
498
tour.onComplete(function(currentStep, reason) {
499
store.dispatch({
500
type: 'TOUR_COMPLETED',
501
payload: { step: currentStep, reason }
502
});
503
});
504
505
return tour;
506
}
507
```
508
509
### Deprecated Callback Methods
510
511
Legacy callback methods maintained for backward compatibility:
512
513
```typescript { .api }
514
/**
515
* @deprecated Use onBeforeChange instead
516
*/
517
onbeforechange(callback: introBeforeChangeCallback): Tour;
518
519
/**
520
* @deprecated Use onChange instead
521
*/
522
onchange(callback: introChangeCallback): Tour;
523
524
/**
525
* @deprecated Use onAfterChange instead
526
*/
527
onafterchange(callback: introAfterChangeCallback): Tour;
528
529
/**
530
* @deprecated Use onComplete instead
531
*/
532
oncomplete(callback: introCompleteCallback): Tour;
533
534
/**
535
* @deprecated Use onStart instead
536
*/
537
onstart(callback: introStartCallback): Tour;
538
539
/**
540
* @deprecated Use onExit instead
541
*/
542
onexit(callback: introExitCallback): Tour;
543
544
/**
545
* @deprecated Use onSkip instead
546
*/
547
onskip(callback: introSkipCallback): Tour;
548
549
/**
550
* @deprecated Use onBeforeExit instead
551
*/
552
onbeforeexit(callback: introBeforeExitCallback): Tour;
553
554
/**
555
* @deprecated Use onHintsAdded instead
556
*/
557
onhintsadded(callback: hintsAddedCallback): Hint;
558
559
/**
560
* @deprecated Use onHintClick instead
561
*/
562
onhintclick(callback: hintClickCallback): Hint;
563
564
/**
565
* @deprecated Use onHintClose instead
566
*/
567
onhintclose(callback: hintCloseCallback): Hint;
568
```