Skip to content

Commit 4e87108

Browse files
committed
Allow Tooltips/Popovers to work in shadow DOM
1 parent 2b86193 commit 4e87108

File tree

4 files changed

+62
-2
lines changed

4 files changed

+62
-2
lines changed

js/src/tooltip.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,9 @@ const Tooltip = (($) => {
246246
if (this.isWithContent() && this._isEnabled) {
247247
$(this.element).trigger(showEvent)
248248

249+
const shadowRoot = Util.findShadowRoot(this.element)
249250
const isInTheDom = $.contains(
250-
this.element.ownerDocument.documentElement,
251+
shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement,
251252
this.element
252253
)
253254

js/src/util.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,25 @@ const Util = (($) => {
136136
}
137137
}
138138
}
139+
},
140+
141+
findShadowRoot(element) {
142+
// Can find the shadow root otherwise it'll return the document
143+
if (typeof element.getRootNode === 'function') {
144+
const tmpRoot = element.getRootNode()
145+
return tmpRoot instanceof ShadowRoot ? tmpRoot : null
146+
}
147+
148+
if (element instanceof ShadowRoot) {
149+
return element
150+
}
151+
152+
// when we don't find a shadow root
153+
if (!element.parentNode) {
154+
return null
155+
}
156+
157+
return Util.findShadowRoot(element.parentNode)
139158
}
140159
}
141160

js/tests/unit/util.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,24 @@ $(function () {
5555
id2 = Util.getUID('test')
5656
assert.ok(id !== id2, id + ' !== ' + id2)
5757
})
58+
59+
QUnit.test('Util.findShadowRoot should find the shadow DOM root', function (assert) {
60+
// Only for newer browsers
61+
if (typeof document.body.attachShadow !== 'function') {
62+
assert.expect(0)
63+
return
64+
}
65+
66+
assert.expect(2)
67+
var $div = $('<div id="test"></div>').appendTo($('#qunit-fixture'))
68+
var shadowRoot = $div[0].attachShadow({
69+
mode: 'open'
70+
})
71+
72+
assert.equal(shadowRoot, Util.findShadowRoot(shadowRoot))
73+
74+
shadowRoot.innerHTML = '<button>Shadow Button</button>'
75+
76+
assert.equal(shadowRoot, Util.findShadowRoot(shadowRoot.firstChild))
77+
})
5878
})

js/tests/visual/tooltip.html

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ <h1>Tooltip <small>Bootstrap Visual Test</small></h1>
4747
Tooltip with HTML
4848
</button>
4949
</p>
50-
<div id="target" title="Test tooltip on transformed element"></div>
50+
<div class="row">
51+
<div class="col-sm-3">
52+
<div id="target" title="Test tooltip on transformed element"></div>
53+
</div>
54+
<div id="shadow" class="pt-5"></div>
55+
</div>
5156
</div>
5257

5358
<script src="../../../assets/js/vendor/jquery-slim.min.js"></script>
@@ -57,6 +62,21 @@ <h1>Tooltip <small>Bootstrap Visual Test</small></h1>
5762

5863
<script>
5964
$(function () {
65+
if (typeof document.body.attachShadow === 'function') {
66+
var shadowRoot = $('#shadow')[0].attachShadow({ mode: 'open' })
67+
shadowRoot.innerHTML =
68+
'<button type="button" class="btn btn-secondary" data-toggle="tooltip" data-placement="top" title="Tooltip on top in a shadow dom">' +
69+
' Tooltip on top in a shadow dom' +
70+
'</button>' +
71+
'<button id="secondTooltip" type="button" class="btn btn-secondary" data-toggle="tooltip" data-placement="top" title="Tooltip on top in a shadow dom with container option">' +
72+
' Tooltip on top in a shadow dom' +
73+
'</button>'
74+
75+
$(shadowRoot.firstChild).tooltip()
76+
$(shadowRoot.getElementById('secondTooltip')).tooltip({
77+
container: shadowRoot
78+
})
79+
}
6080
$('[data-toggle="tooltip"]').tooltip()
6181
$('#target').tooltip({
6282
placement : 'top',

0 commit comments

Comments
 (0)