This tutorial explains how to integrate widgets inside a ShadowDOM container, focusing on two key requirements:
- Passing a DOM Element Reference to
SIR('addWidget')
- Cloning Widget Styles into the ShadowDOM using a MutationObserver
1. Passing a DOM Element Reference to SIR('addWidget')
When working with ShadowDOM, CSS selectors may not work as expected because the ShadowDOM encapsulates its contents. Instead of passing a selector string, you should pass a direct reference to the container DOM element.
Example:
// Create a ShadowDOM root and widget container
const host = document.getElementById('widget-host');
const shadowRoot = host.attachShadow({ mode: 'open' }); // also works with { mode: 'closed' }
const widgetContainer = document.createElement('div');
shadowRoot.appendChild(widgetContainer);
// Include widgetloader snippet
(function(a,b,c,d,e,f,g,h,i){a[e]||(i=a[e]=function(){(a[e].q=a[e].q||[]).push(arguments)},i.l=1*new Date,i.o=f,
g=b.createElement(c),h=b.getElementsByTagName(c)[0],g.async=1,g.src=d,g.setAttribute("n",e),h.parentNode.insertBefore(g,h)
)})(window,document,"script","https://widgets.sir.sportradar.com/[CLIENT_ID]/widgetloader","SIR",{
theme: 'default',
language: 'en'
});
// Pass the `widgetContainer` DOM Element reference to SIR('addWidget')
SIR('addWidget', widgetContainer, 'match.lmtPlus', {
matchId: MATCH_ID_HERE,
// additional config options here.
});
2. Cloning Widget Styles into the ShadowDOM
Widgets inject <link>
elements into the document <head>
. These styles are not visible inside the ShadowDOM by default. To ensure proper styling, you need to clone these style elements into the ShadowDOM container.
Note: Only
<link>
elements whosehref
containswidgets.sir.sportradar.com
should be cloned into the ShadowDOM. This ensures that only widget-specific styles are included, avoiding unnecessary or conflicting styles from other sources.
Setting Up a MutationObserver
A MutationObserver
can watch for new <link>
elements in <head>
and clone them into the ShadowDOM.
Example:
// Create specific container for `<link>` elements in Shadow DOM
const linkContainer = document.createElement('div');
shadowRoot.appendChild(linkContainer);
// Set up MutationObserver to watch for changes in <head> and move styles to Shadow DOM
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
// Only clone <link> elements with "https://widgets.sir.sportradar.com" in "href"
if (node.tagName === 'LINK' && node.rel === 'stylesheet' && node.href.includes('https://widgets.sir.sportradar.com')) {
linkContainer.appendChild(node.cloneNode());
}
// Clone the <style> element with id "sr-client-theme". This part is only needed if `theme` option is used in the widgetloader
if (node.tagName === "STYLE" && node.id === "sr-client-theme") {
const clonedNode = node.cloneNode(true); // also copy the content
clonedNode.id = "sr-client-theme-clone";
// Client theme should be positioned last in the ShadowDOM (after `linkContainer` containing all other <link> elements)
// to make sure styles are applied in correct order.
shadowRoot.appendChild(clonedNode);
}
});
});
});
observer.observe(document.head, { childList: true });
Note: Set up
MutationObserver
before calling widgetloader to make sure all Widget styles are cloned inside ShadowDOM after widget is initialised.
Full Integration Example
<div id="widget-host"></div>
<script>
// 1. Create a ShadowDOM root and widget container
const host = document.getElementById('widget-host');
const shadowRoot = host.attachShadow({ mode: 'open' }); // also works with { mode: 'closed' }
const widgetContainer = document.createElement('div');
shadowRoot.appendChild(widgetContainer);
// 2. Set up MutationObserver to clone Widget styles into ShadowDOM
const linkContainer = document.createElement('div');
shadowRoot.appendChild(linkContainer);
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
// Only clone <link> elements with "https://widgets.sir.sportradar.com" in "href"
if (node.tagName === 'LINK' && node.rel === 'stylesheet' && node.href.includes('https://widgets.sir.sportradar.com')) {
linkContainer.appendChild(node.cloneNode());
}
// Clone the <style> element with id "sr-client-theme". This part is only needed if `theme` option is used in the widgetloader
if (node.tagName === "STYLE" && node.id === "sr-client-theme") {
const clonedNode = node.cloneNode(true); // also copy the content
clonedNode.id = "sr-client-theme-clone";
// Client theme should be positioned last in the ShadowDOM (after `linkContainer` containing all other <link> elements)
// to make sure styles are applied in correct order.
shadowRoot.appendChild(clonedNode);
}
});
});
});
observer.observe(document.head, { childList: true });
// 3. Include widgetloader and initialise widget
(function(a,b,c,d,e,f,g,h,i){a[e]||(i=a[e]=function(){(a[e].q=a[e].q||[]).push(arguments)},i.l=1*new Date,i.o=f,
g=b.createElement(c),h=b.getElementsByTagName(c)[0],g.async=1,g.src=d,g.setAttribute("n",e),h.parentNode.insertBefore(g,h)
)})(window,document,"script","https://widgets.sir.sportradar.com/[CLIENT_ID]/widgetloader","SIR",{
theme: 'default',
language: 'en',
});
// Pass the `widgetContainer` DOM Element reference to SIR('addWidget')
SIR('addWidget', widgetContainer, 'match.lmtPlus', {
matchId: MATCH_ID_HERE,
// additional config options here.
});
</script>
Summary
- Always pass a DOM element reference to
SIR('addWidget')
when using ShadowDOM. - Use a MutationObserver to clone widget-related
<link>
elements from<head>
into the ShadowDOM container.
This ensures your widgets render and style correctly inside ShadowDOM.