This tutorial is for:
By completing this tutorial, you will:
Before starting this tutorial, ensure you have:
attachShadow, shadow roots)ShadowDOM is supported in all modern browsers. Legacy browsers (IE11) do not support ShadowDOM and require polyfills.
ShadowDOM provides style and DOM encapsulation for web components, but this encapsulation presents two challenges for widget integration:
<head> are not visible inside ShadowDOM, so they need to be cloned into the ShadowDOM.This tutorial shows you how to overcome both challenges.
First, create a host element and attach a shadow root to it. Then create a container element inside the shadow root where the widget will be rendered.
<div id="widget-host"></div>const host = document.getElementById('widget-host');
const shadowRoot = host.attachShadow({ mode: 'open' });
const widgetContainer = document.createElement('div');
shadowRoot.appendChild(widgetContainer);Both { mode: 'open' } and { mode: 'closed' } work with this approach. The widget framework doesn't need access to the shadow root after initialization.
When working with ShadowDOM, you cannot use CSS selector strings with SIR('addWidget'). Instead, pass a direct reference to the container DOM element.
❌ This will NOT work:
SIR('addWidget', '#widget-container', 'match.lmtPlus', { ... });✅ This WILL work:
SIR('addWidget', widgetContainer, 'match.lmtPlus', { ... });Example initialization:
// Include widgetloader
(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'
});
SIR('addWidget', widgetContainer, 'match.lmtPlus', {
matchId: 'your_match_id_here'
});Replace [CLIENT_ID] with your actual client ID and your_match_id_here with a valid match identifier.
Create a dedicated container inside the ShadowDOM to hold the cloned <link> elements.
const widgetContainer = document.createElement('div');
const linkContainer = document.createElement('div');
shadowRoot.appendChild(linkContainer);
shadowRoot.appendChild(widgetContainer);The linkContainer should be added before the widgetContainer to ensure styles are loaded in the correct order.
Widgets inject <link> and <style> elements into the document <head>. These styles are not visible inside ShadowDOM by default. Use a MutationObserver to detect and clone these elements.
Only clone widget-specific styles to avoid conflicts:
<link> elements with href containing widgets.sir.sportradar.com<style> element with id="sr-client-theme" (only when using custom themes)const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
// Clone widget stylesheet links
if (node.tagName === 'LINK' &&
node.rel === 'stylesheet' &&
node.href.includes('https://widgets.sir.sportradar.com')) {
linkContainer.appendChild(node.cloneNode());
}
// Clone client theme styles (only if using custom theme)
if (node.tagName === "STYLE" && node.id === "sr-client-theme") {
const clonedNode = node.cloneNode(true);
clonedNode.id = "sr-client-theme-clone";
// Append after linkContainer to maintain style precedence
shadowRoot.appendChild(clonedNode);
}
});
});
});
observer.observe(document.head, { childList: true });Critical: Set up the MutationObserver before calling the widgetloader to ensure all styles are captured during widget initialization.
Now that the observer is in place, initialize the widget as shown in Step 2. The observer will automatically clone styles as they are added to the document.
SIR('addWidget', widgetContainer, 'match.lmtPlus', {
matchId: 'your_match_id_here'
});View Complete Working Example
Here's the full implementation combining all steps:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ShadowDOM Widget Integration</title>
</head>
<body>
<div id="widget-host"></div>
<script>
// Step 1: Create ShadowDOM container
const host = document.getElementById('widget-host');
const shadowRoot = host.attachShadow({ mode: 'open' });
// Step 3: Create containers for styles and widget
const linkContainer = document.createElement('div');
const widgetContainer = document.createElement('div');
shadowRoot.appendChild(linkContainer);
shadowRoot.appendChild(widgetContainer);
// Step 4: Set up MutationObserver (BEFORE widgetloader)
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
// Clone widget stylesheet links
if (node.tagName === 'LINK' &&
node.rel === 'stylesheet' &&
node.href.includes('https://widgets.sir.sportradar.com')) {
linkContainer.appendChild(node.cloneNode());
}
// Clone client theme styles
if (node.tagName === "STYLE" && node.id === "sr-client-theme") {
const clonedNode = node.cloneNode(true);
clonedNode.id = "sr-client-theme-clone";
shadowRoot.appendChild(clonedNode);
}
});
});
});
observer.observe(document.head, { childList: true });
// Step 2 & 5: Initialize widgetloader and add 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 DOM element reference (not selector string)
SIR('addWidget', widgetContainer, 'match.lmtPlus', {
matchId: 'your_match_id_here'
});
</script>
</body>
</html>Replace [CLIENT_ID] with your actual client ID and your_match_id_here with a valid match identifier.
Always pass a direct DOM element reference to SIR('addWidget') when using ShadowDOM. CSS selector strings cannot penetrate shadow boundaries.
Use MutationObserver to clone widget-specific <link> and <style> elements from <head> into the ShadowDOM container.
Set up the MutationObserver before loading the widgetloader script to capture all style elements during initialization.