Betting Entertainment Tools

Integration of Widgets within a ShadowDOM Container

This tutorial explains how to integrate widgets inside a ShadowDOM container, focusing on two key requirements:

  1. Passing a DOM Element Reference to SIR('addWidget')
  2. 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 whose href contains widgets.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.