0
# Overlays & Popovers
1
2
Overlay components including tooltips, popovers, and advanced positioning for contextual information display.
3
4
## Capabilities
5
6
### Tooltip
7
8
Bootstrap tooltip functionality with extensive configuration and positioning options.
9
10
```typescript { .api }
11
/**
12
* Tooltip directive for displaying contextual information
13
*/
14
@Directive({
15
selector: '[tooltip], [tooltipHtml]'
16
})
17
class TooltipDirective implements OnInit, OnDestroy {
18
/** Tooltip content */
19
@Input() tooltip: string | TemplateRef<any>;
20
/** HTML tooltip content */
21
@Input() tooltipHtml: string | TemplateRef<any>;
22
/** Tooltip placement */
23
@Input() placement: string = 'top';
24
/** Trigger events */
25
@Input() triggers: string = 'hover focus';
26
/** Container for tooltip */
27
@Input() container: string = 'body';
28
/** Disable tooltip */
29
@Input() isDisabled: boolean = false;
30
/** Show/hide delay */
31
@Input() delay: number = 0;
32
/** Custom CSS class */
33
@Input() customClass: string = '';
34
/** Tooltip context for template */
35
@Input() tooltipContext: any;
36
/** Popup delay */
37
@Input() tooltipPopupDelay: number = 0;
38
/** Fade transition */
39
@Input() tooltipFadeDuration: number = 150;
40
/** Enable adaptive positioning */
41
@Input() adaptivePosition: boolean = true;
42
43
/** Event emitted when tooltip is shown */
44
@Output() onShown: EventEmitter<TooltipDirective> = new EventEmitter();
45
/** Event emitted when tooltip is hidden */
46
@Output() onHidden: EventEmitter<TooltipDirective> = new EventEmitter();
47
/** Event emitted when tooltip state changes */
48
@Output() tooltipStateChanged: EventEmitter<boolean> = new EventEmitter();
49
50
/** Show tooltip */
51
show(): void;
52
/** Hide tooltip */
53
hide(): void;
54
/** Toggle tooltip */
55
toggle(): void;
56
/** Check if tooltip is open */
57
isOpen(): boolean;
58
}
59
60
/**
61
* Tooltip container component
62
*/
63
@Component({
64
selector: 'bs-tooltip-container'
65
})
66
class TooltipContainerComponent implements OnInit {
67
/** Tooltip placement */
68
placement: string;
69
/** Tooltip content */
70
htmlContent: string | TemplateRef<any>;
71
/** Content template */
72
content: string | TemplateRef<any>;
73
/** CSS classes */
74
classMap: { [key: string]: boolean };
75
/** Animation state */
76
animationState: string;
77
/** Show state */
78
show: boolean;
79
}
80
81
/**
82
* Global configuration for tooltips
83
*/
84
@Injectable()
85
class TooltipConfig {
86
/** Default placement */
87
placement: string = 'top';
88
/** Default triggers */
89
triggers: string = 'hover focus';
90
/** Default container */
91
container: string = 'body';
92
/** Default delay */
93
delay: number = 0;
94
/** Default adaptive positioning */
95
adaptivePosition: boolean = true;
96
}
97
98
/**
99
* Angular module for tooltip functionality
100
*/
101
@NgModule({
102
declarations: [TooltipDirective, TooltipContainerComponent],
103
exports: [TooltipDirective]
104
})
105
class TooltipModule {}
106
```
107
108
**Usage Example:**
109
110
```typescript
111
import { TooltipModule } from 'ngx-bootstrap/tooltip';
112
113
@Component({
114
template: `
115
<!-- Basic tooltip -->
116
<button
117
type="button"
118
class="btn btn-primary"
119
tooltip="This is a tooltip">
120
Hover for tooltip
121
</button>
122
123
<!-- HTML tooltip -->
124
<button
125
type="button"
126
class="btn btn-info"
127
tooltipHtml="<strong>Bold</strong> and <em>italic</em> text"
128
placement="bottom"
129
triggers="click">
130
Click for HTML tooltip
131
</button>
132
133
<!-- Template tooltip -->
134
<button
135
type="button"
136
class="btn btn-success"
137
[tooltip]="tooltipTemplate"
138
[tooltipContext]="tooltipData"
139
placement="right"
140
customClass="custom-tooltip">
141
Template tooltip
142
</button>
143
144
<ng-template #tooltipTemplate let-data="data">
145
<div>
146
<h6>{{data.title}}</h6>
147
<p>{{data.description}}</p>
148
<small>{{data.timestamp}}</small>
149
</div>
150
</ng-template>
151
152
<!-- Conditional tooltip -->
153
<button
154
type="button"
155
class="btn btn-warning"
156
tooltip="Conditional tooltip"
157
[isDisabled]="tooltipDisabled"
158
[delay]="500"
159
(onShown)="onTooltipShown()"
160
(onHidden)="onTooltipHidden()">
161
Conditional tooltip
162
</button>
163
`,
164
imports: [TooltipModule]
165
})
166
export class MyComponent {
167
tooltipDisabled = false;
168
169
tooltipData = {
170
title: 'Custom Tooltip',
171
description: 'This is a template-based tooltip with custom data.',
172
timestamp: new Date().toLocaleString()
173
};
174
175
onTooltipShown() {
176
console.log('Tooltip shown');
177
}
178
179
onTooltipHidden() {
180
console.log('Tooltip hidden');
181
}
182
183
toggleTooltip() {
184
this.tooltipDisabled = !this.tooltipDisabled;
185
}
186
}
187
```
188
189
### Popover
190
191
Bootstrap popover functionality for displaying rich content in overlay containers.
192
193
```typescript { .api }
194
/**
195
* Popover directive for displaying rich contextual content
196
*/
197
@Directive({
198
selector: '[popover], [popoverHtml]'
199
})
200
class PopoverDirective implements OnInit, OnDestroy {
201
/** Popover content */
202
@Input() popover: string | TemplateRef<any>;
203
/** HTML popover content */
204
@Input() popoverHtml: string | TemplateRef<any>;
205
/** Popover title */
206
@Input() popoverTitle: string;
207
/** Popover placement */
208
@Input() placement: string = 'top';
209
/** Trigger events */
210
@Input() triggers: string = 'click';
211
/** Container for popover */
212
@Input() container: string = 'body';
213
/** Disable popover */
214
@Input() isDisabled: boolean = false;
215
/** Show/hide delay */
216
@Input() delay: number = 0;
217
/** Custom CSS class */
218
@Input() customClass: string = '';
219
/** Popover context for template */
220
@Input() popoverContext: any;
221
/** Close on outside click */
222
@Input() outsideClick: boolean = false;
223
/** Enable adaptive positioning */
224
@Input() adaptivePosition: boolean = true;
225
226
/** Event emitted when popover is shown */
227
@Output() onShown: EventEmitter<PopoverDirective> = new EventEmitter();
228
/** Event emitted when popover is hidden */
229
@Output() onHidden: EventEmitter<PopoverDirective> = new EventEmitter();
230
231
/** Show popover */
232
show(): void;
233
/** Hide popover */
234
hide(): void;
235
/** Toggle popover */
236
toggle(): void;
237
/** Check if popover is open */
238
isOpen(): boolean;
239
}
240
241
/**
242
* Popover container component
243
*/
244
@Component({
245
selector: 'popover-container'
246
})
247
class PopoverContainerComponent implements OnInit {
248
/** Popover placement */
249
placement: string;
250
/** Popover title */
251
title: string;
252
/** HTML content */
253
htmlContent: string | TemplateRef<any>;
254
/** Content template */
255
content: string | TemplateRef<any>;
256
/** CSS classes */
257
classMap: { [key: string]: boolean };
258
/** Animation state */
259
containerClass: string;
260
/** Show state */
261
show: boolean;
262
}
263
264
/**
265
* Global configuration for popovers
266
*/
267
@Injectable()
268
class PopoverConfig {
269
/** Default placement */
270
placement: string = 'top';
271
/** Default triggers */
272
triggers: string = 'click';
273
/** Default container */
274
container: string = 'body';
275
/** Default delay */
276
delay: number = 0;
277
/** Default adaptive positioning */
278
adaptivePosition: boolean = true;
279
}
280
281
/**
282
* Angular module for popover functionality
283
*/
284
@NgModule({
285
declarations: [PopoverDirective, PopoverContainerComponent],
286
exports: [PopoverDirective]
287
})
288
class PopoverModule {}
289
```
290
291
**Usage Example:**
292
293
```typescript
294
import { PopoverModule } from 'ngx-bootstrap/popover';
295
296
@Component({
297
template: `
298
<!-- Basic popover -->
299
<button
300
type="button"
301
class="btn btn-primary"
302
popover="This is popover content"
303
popoverTitle="Popover Title"
304
placement="bottom">
305
Click for popover
306
</button>
307
308
<!-- HTML popover -->
309
<button
310
type="button"
311
class="btn btn-info"
312
popoverHtml="<strong>HTML content</strong><br><em>with formatting</em>"
313
popoverTitle="HTML Popover"
314
placement="right"
315
triggers="hover">
316
Hover for HTML popover
317
</button>
318
319
<!-- Template popover -->
320
<button
321
type="button"
322
class="btn btn-success"
323
[popover]="popoverTemplate"
324
[popoverContext]="popoverData"
325
popoverTitle="Custom Popover"
326
placement="left"
327
customClass="custom-popover"
328
[outsideClick]="true">
329
Template popover
330
</button>
331
332
<ng-template #popoverTemplate let-data="data">
333
<div class="popover-content">
334
<ul class="list-unstyled">
335
<li><strong>Name:</strong> {{data.name}}</li>
336
<li><strong>Email:</strong> {{data.email}}</li>
337
<li><strong>Status:</strong>
338
<span [class]="'badge badge-' + data.statusClass">
339
{{data.status}}
340
</span>
341
</li>
342
</ul>
343
<div class="mt-2">
344
<button class="btn btn-sm btn-primary" (click)="editUser(data)">
345
Edit
346
</button>
347
<button class="btn btn-sm btn-secondary ml-1" (click)="viewProfile(data)">
348
View Profile
349
</button>
350
</div>
351
</div>
352
</ng-template>
353
354
<!-- Programmatic popover -->
355
<button
356
type="button"
357
class="btn btn-warning"
358
#programmaticPopover="bs-popover"
359
popover="Programmatically controlled"
360
popoverTitle="Manual Control"
361
triggers="manual"
362
(onShown)="onPopoverShown()"
363
(onHidden)="onPopoverHidden()">
364
Manual popover
365
</button>
366
367
<div class="mt-2">
368
<button class="btn btn-sm btn-success" (click)="programmaticPopover.show()">
369
Show
370
</button>
371
<button class="btn btn-sm btn-danger ml-1" (click)="programmaticPopover.hide()">
372
Hide
373
</button>
374
<button class="btn btn-sm btn-info ml-1" (click)="programmaticPopover.toggle()">
375
Toggle
376
</button>
377
</div>
378
`,
379
imports: [PopoverModule]
380
})
381
export class MyComponent {
382
popoverData = {
383
name: 'John Doe',
384
email: 'john.doe@example.com',
385
status: 'Active',
386
statusClass: 'success'
387
};
388
389
onPopoverShown() {
390
console.log('Popover shown');
391
}
392
393
onPopoverHidden() {
394
console.log('Popover hidden');
395
}
396
397
editUser(user: any) {
398
console.log('Editing user:', user);
399
}
400
401
viewProfile(user: any) {
402
console.log('Viewing profile:', user);
403
}
404
}
405
```
406
407
### Advanced Dropdown
408
409
Extended dropdown functionality beyond the basic dropdown covered in Interactive Components.
410
411
```typescript { .api }
412
/**
413
* Advanced dropdown configurations and utilities
414
*/
415
interface BsDropdownMenuDirective {
416
/** Template reference */
417
templateRef: TemplateRef<any>;
418
/** Location in DOM */
419
location: ElementRef;
420
}
421
422
/**
423
* Dropdown container component for advanced scenarios
424
*/
425
@Component({
426
selector: 'bs-dropdown-container'
427
})
428
class BsDropdownContainerComponent implements OnInit, OnDestroy {
429
/** Dropdown placement */
430
placement: string;
431
/** CSS classes */
432
classMap: { [key: string]: boolean };
433
/** Animation state */
434
direction: 'down' | 'up';
435
/** Host element */
436
hostElement: ElementRef;
437
438
/** Get dropdown classes */
439
get dropdownClass(): { [key: string]: boolean };
440
/** Position dropdown */
441
position(): void;
442
/** Show dropdown */
443
show(): void;
444
/** Hide dropdown */
445
hide(): void;
446
}
447
448
/**
449
* Advanced dropdown state with additional properties
450
*/
451
interface BsDropdownState {
452
/** Dropdown direction */
453
direction: 'down' | 'up';
454
/** Auto close behavior */
455
autoClose: boolean | 'outside' | 'inside';
456
/** Inside click handling */
457
insideClick: boolean;
458
/** Open state change emitter */
459
isOpenChange: EventEmitter<boolean>;
460
/** Animation enabled */
461
isAnimated: boolean;
462
/** Stop on outside click */
463
stopOnOutsideClick: boolean;
464
/** Keyboard navigation */
465
keyboardNav: boolean;
466
/** Toggle click emitter */
467
toggleClick: EventEmitter<boolean>;
468
/** Counts of dropdowns */
469
counts: number;
470
}
471
472
/**
473
* Dropdown events interface
474
*/
475
interface BsDropdownEvents {
476
/** Before show event */
477
onBeforeShow?: () => void;
478
/** After show event */
479
onAfterShow?: () => void;
480
/** Before hide event */
481
onBeforeHide?: () => void;
482
/** After hide event */
483
onAfterHide?: () => void;
484
}
485
```
486
487
**Advanced Dropdown Usage:**
488
489
```typescript
490
import { BsDropdownModule, BsDropdownConfig } from 'ngx-bootstrap/dropdown';
491
492
@Component({
493
template: `
494
<!-- Dropdown with custom positioning -->
495
<div class="btn-group"
496
bsDropdown
497
[placement]="'bottom-right'"
498
[autoClose]="'outside'"
499
(onShown)="onDropdownShown()"
500
(onHidden)="onDropdownHidden()">
501
502
<button class="btn btn-primary dropdown-toggle" bsDropdownToggle>
503
Advanced Dropdown <span class="caret"></span>
504
</button>
505
506
<div *bsDropdownMenu class="dropdown-menu" role="menu">
507
<h6 class="dropdown-header">Navigation</h6>
508
<a class="dropdown-item" href="#" (click)="handleAction('home')">Home</a>
509
<a class="dropdown-item" href="#" (click)="handleAction('profile')">Profile</a>
510
<div class="dropdown-divider"></div>
511
<h6 class="dropdown-header">Actions</h6>
512
<a class="dropdown-item" href="#" (click)="handleAction('settings')">Settings</a>
513
<a class="dropdown-item" href="#" (click)="handleAction('logout')">Logout</a>
514
</div>
515
</div>
516
517
<!-- Nested dropdown -->
518
<div class="btn-group"
519
bsDropdown
520
[container]="'body'"
521
[insideClick]="true">
522
523
<button class="btn btn-secondary dropdown-toggle" bsDropdownToggle>
524
Nested Menu <span class="caret"></span>
525
</button>
526
527
<div *bsDropdownMenu class="dropdown-menu">
528
<div class="dropdown-submenu">
529
<a class="dropdown-item dropdown-toggle"
530
bsDropdown
531
[placement]="'right-top'">
532
Submenu
533
</a>
534
<div *bsDropdownMenu class="dropdown-menu">
535
<a class="dropdown-item" href="#">Submenu Item 1</a>
536
<a class="dropdown-item" href="#">Submenu Item 2</a>
537
</div>
538
</div>
539
<a class="dropdown-item" href="#">Regular Item</a>
540
</div>
541
</div>
542
`,
543
imports: [BsDropdownModule]
544
})
545
export class AdvancedDropdownComponent {
546
constructor(private dropdownConfig: BsDropdownConfig) {
547
// Configure global dropdown behavior
548
this.dropdownConfig.autoClose = 'outside';
549
this.dropdownConfig.isAnimated = true;
550
}
551
552
onDropdownShown() {
553
console.log('Advanced dropdown shown');
554
}
555
556
onDropdownHidden() {
557
console.log('Advanced dropdown hidden');
558
}
559
560
handleAction(action: string) {
561
console.log('Dropdown action:', action);
562
}
563
}
564
```
565
566
### Focus Trap
567
568
Focus trapping functionality for modal-like components and accessibility.
569
570
```typescript { .api }
571
/**
572
* Focus trap directive for accessibility
573
*/
574
@Directive({
575
selector: '[focusTrap]'
576
})
577
class FocusTrapDirective implements OnInit, OnDestroy {
578
/** Enable/disable focus trap */
579
@Input() focusTrap: boolean = true;
580
581
/** First focusable element */
582
private firstFocusableElement: HTMLElement;
583
/** Last focusable element */
584
private lastFocusableElement: HTMLElement;
585
/** Previously focused element */
586
private previouslyFocusedElement: HTMLElement;
587
588
/** Set focus to first element */
589
focusFirstElement(): void;
590
/** Set focus to last element */
591
focusLastElement(): void;
592
/** Get focusable elements */
593
getFocusableElements(): HTMLElement[];
594
/** Handle tab key navigation */
595
handleTabKey(event: KeyboardEvent): void;
596
}
597
598
/**
599
* Focus trap service for programmatic control
600
*/
601
@Injectable()
602
class FocusTrap {
603
/** Current trapped element */
604
private trappedElement: HTMLElement;
605
606
/** Enable focus trap on element */
607
enable(element: HTMLElement): void;
608
/** Disable focus trap */
609
disable(): void;
610
/** Check if focus trap is active */
611
isActive(): boolean;
612
/** Get trapped element */
613
getTrappedElement(): HTMLElement;
614
}
615
616
/**
617
* Angular module for focus trap functionality
618
*/
619
@NgModule({
620
declarations: [FocusTrapDirective],
621
exports: [FocusTrapDirective],
622
providers: [FocusTrap]
623
})
624
class FocusTrapModule {}
625
```
626
627
**Usage Example:**
628
629
```typescript
630
import { FocusTrapModule, FocusTrap } from 'ngx-bootstrap/focus-trap';
631
632
@Component({
633
template: `
634
<!-- Modal with focus trap -->
635
<div class="modal"
636
[class.show]="showModal"
637
[style.display]="showModal ? 'block' : 'none'"
638
focusTrap
639
[focusTrap]="showModal">
640
641
<div class="modal-dialog">
642
<div class="modal-content">
643
<div class="modal-header">
644
<h5 class="modal-title">Focus Trapped Modal</h5>
645
<button type="button"
646
class="btn-close"
647
(click)="closeModal()"
648
aria-label="Close">
649
<span aria-hidden="true">×</span>
650
</button>
651
</div>
652
653
<div class="modal-body">
654
<form>
655
<div class="mb-3">
656
<label for="firstName" class="form-label">First Name</label>
657
<input type="text"
658
class="form-control"
659
id="firstName"
660
#firstInput>
661
</div>
662
663
<div class="mb-3">
664
<label for="lastName" class="form-label">Last Name</label>
665
<input type="text"
666
class="form-control"
667
id="lastName">
668
</div>
669
670
<div class="mb-3">
671
<label for="email" class="form-label">Email</label>
672
<input type="email"
673
class="form-control"
674
id="email">
675
</div>
676
</form>
677
</div>
678
679
<div class="modal-footer">
680
<button type="button"
681
class="btn btn-secondary"
682
(click)="closeModal()">
683
Cancel
684
</button>
685
<button type="button"
686
class="btn btn-primary"
687
(click)="saveForm()">
688
Save
689
</button>
690
</div>
691
</div>
692
</div>
693
</div>
694
695
<!-- Trigger button -->
696
<button class="btn btn-primary"
697
(click)="openModal()"
698
[disabled]="showModal">
699
Open Focus Trapped Modal
700
</button>
701
702
<!-- Programmatic focus trap -->
703
<div class="card mt-3" #trapContainer>
704
<div class="card-body">
705
<h6 class="card-title">Programmatic Focus Trap</h6>
706
<div class="form-group">
707
<input type="text"
708
class="form-control mb-2"
709
placeholder="Input 1">
710
<input type="text"
711
class="form-control mb-2"
712
placeholder="Input 2">
713
<button class="btn btn-primary me-2"
714
(click)="enableTrap()">
715
Enable Trap
716
</button>
717
<button class="btn btn-secondary"
718
(click)="disableTrap()">
719
Disable Trap
720
</button>
721
</div>
722
</div>
723
</div>
724
`,
725
imports: [FocusTrapModule]
726
})
727
export class FocusTrapExampleComponent {
728
showModal = false;
729
730
constructor(private focusTrap: FocusTrap) {}
731
732
@ViewChild('firstInput') firstInput: ElementRef;
733
@ViewChild('trapContainer') trapContainer: ElementRef;
734
735
openModal() {
736
this.showModal = true;
737
// Focus will be automatically trapped when modal becomes visible
738
setTimeout(() => {
739
this.firstInput?.nativeElement.focus();
740
}, 100);
741
}
742
743
closeModal() {
744
this.showModal = false;
745
}
746
747
saveForm() {
748
console.log('Form saved');
749
this.closeModal();
750
}
751
752
enableTrap() {
753
this.focusTrap.enable(this.trapContainer.nativeElement);
754
}
755
756
disableTrap() {
757
this.focusTrap.disable();
758
}
759
}
760
```