npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@krasnoff/react-shadow-dom-component

v1.0.0

Published

Implementation of a react shadow-dom component template using vite for npm package distribution

Readme

React Shadow DOM Template Component

A React component that enables easy integration of Shadow DOM functionality in your React applications. This component provides a declarative way to create and manage Shadow DOM with full React compatibility.

Features

  • 🔒 Shadow DOM Encapsulation - Isolate styles and DOM structure
  • ⚛️ React Compatible - Render React components inside Shadow DOM
  • 🎨 Styling Support - Use CSS Stylesheets with adoptedStyleSheets
  • ⚙️ Configurable - Full control over Shadow DOM options
  • 🔄 Dynamic Updates - Automatically handles prop changes and remounting

Installation

npm i @krasnoff/react-shadow-dom-component

Basic Usage

import React from 'react';
import { Template } from '@krasnoff/react-shadow-dom-component'

function App() {
  return (
    <Template shadowrootmode="open">
      <div style={{ padding: '20px', backgroundColor: 'lightblue' }}>
        <h1>This content is rendered inside Shadow DOM!</h1>
        <p>Styles are encapsulated and won't affect the parent document.</p>
      </div>
    </Template>
  );
}

Advanced Usage with CSS Stylesheets

import React from 'react';
import { Template } from '@krasnoff/react-shadow-dom-component'

function StyledComponent() {
  // Create a CSS stylesheet for the Shadow DOM
  const stylesheet = new CSSStyleSheet();
  stylesheet.replaceSync(`
    .container {
      background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
      padding: 2rem;
      border-radius: 10px;
      color: white;
      font-family: Arial, sans-serif;
    }
    .title {
      font-size: 2rem;
      margin-bottom: 1rem;
    }
  `);

  return (
    <Template 
      shadowrootmode="open" 
      sheet={stylesheet}
      shadowrootdelegatesfocus={true}
    >
      <div className="container">
        <h1 className="title">Styled Shadow DOM Content</h1>
        <p>This component uses adopted stylesheets for styling.</p>
        <button>This button won't be styled by parent CSS!</button>
      </div>
    </Template>
  );
}

Component API

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | children | React.ReactNode | undefined | React elements to render inside the Shadow DOM | | shadowrootmode | 'open' \| 'closed' | 'open' | Shadow DOM mode - 'open' allows external access, 'closed' doesn't | | sheet | CSSStyleSheet | undefined | CSS stylesheet to apply to the Shadow DOM using adoptedStyleSheets | | shadowrootclonable | boolean | false | Whether the shadow root can be cloned | | shadowrootdelegatesfocus | boolean | false | Whether focus delegation is enabled | | shadowrootserializable | boolean | false | Whether the shadow root can be serialized | | slotAssignment | 'manual' \| 'named' | 'named' | How slots are assigned in the shadow tree - 'named' for automatic assignment, 'manual' for programmatic control | | connectedCallback | (shadowRoot: ShadowRoot, hostElement: HTMLDivElement) => void | undefined | Callback function executed when Shadow DOM is successfully created and connected |

TypeScript Interface

export interface TemplateProps {
    children?: React.ReactNode;
    shadowrootmode?: 'open' | 'closed';
    sheet?: CSSStyleSheet;
    shadowrootclonable?: boolean;
    shadowrootdelegatesfocus?: boolean;
    shadowrootserializable?: boolean;
    slotAssignment?: 'manual' | 'named';
    connectedCallback?: (shadowRoot: ShadowRoot, hostElement: HTMLDivElement) => void;
}

Use Cases

1. Widget Isolation

Perfect for creating widgets that need to be embedded in third-party websites without style conflicts:

function EmbeddableWidget() {
  const widgetStyles = new CSSStyleSheet();
  widgetStyles.replaceSync(`
    .widget {
      border: 2px solid #007bff;
      padding: 1rem;
      background: white;
      font-family: -apple-system, BlinkMacSystemFont, sans-serif;
    }
  `);

  return (
    <Template shadowrootmode="open" sheet={widgetStyles}>
      <div className="widget">
        <h3>My Embeddable Widget</h3>
        <p>This widget is completely isolated from the host page!</p>
      </div>
    </Template>
  );
}

2. Micro Frontend Components

Isolate micro frontend components to prevent style bleeding:

function MicroFrontend({ apiEndpoint }: { apiEndpoint: string }) {
  const [data, setData] = useState(null);

  const microfrontendStyles = new CSSStyleSheet();
  microfrontendStyles.replaceSync(`
    .micro-app {
      display: flex;
      flex-direction: column;
      gap: 1rem;
    }
    .card { /* ... */ }
  `);

  return (
    <Template 
      shadowrootmode="open" 
      sheet={microfrontendStyles}
      shadowrootdelegatesfocus={true}
    >
      <div className="micro-app">
        {/* Your micro frontend content */}
      </div>
    </Template>
  );
}

3. Library Components with Theme Isolation

function ThemeIsolatedButton({ theme, children, onClick }: ButtonProps) {
  const buttonTheme = new CSSStyleSheet();
  buttonTheme.replaceSync(`
    .theme-button {
      background: ${theme.primaryColor};
      color: ${theme.textColor};
      padding: ${theme.spacing}px;
      border: none;
      border-radius: ${theme.borderRadius}px;
      cursor: pointer;
      font-size: 1rem;
    }
    .theme-button:hover {
      opacity: 0.8;
    }
  `);

  return (
    <Template shadowrootmode="open" sheet={buttonTheme}>
      <button className="theme-button" onClick={onClick}>
        {children}
      </button>
    </Template>
  );
}

4. Using Slot Assignment

Control how slots are assigned within the Shadow DOM:

function SlotAssignmentExample() {
  return (
    <Template 
      shadowrootmode="open" 
      slotAssignment="named"
    >
      <div>
        <h2>Content with Named Slots</h2>
        <slot name="header"></slot>
        <p>Main content area</p>
        <slot name="content"></slot>
        <footer>
          <slot name="footer"></slot>
        </footer>
      </div>
    </Template>
  );
}

// Usage with slotted content
function App() {
  return (
    <SlotAssignmentExample>
      <div slot="header">This goes in the header slot</div>
      <div slot="content">This goes in the content slot</div>
      <div slot="footer">This goes in the footer slot</div>
    </SlotAssignmentExample>
  );
}

5. Using Connected Callback

Execute custom logic when Shadow DOM is created:

function ConnectedCallbackExample() {
  const handleConnected = (shadowRoot: ShadowRoot, hostElement: HTMLDivElement) => {
    console.log('Shadow DOM connected!', shadowRoot);
    
    // Add custom event listeners
    shadowRoot.addEventListener('click', (e) => {
      console.log('Clicked inside Shadow DOM:', e.target);
    });
    
    // Modify host element
    hostElement.style.border = '2px solid #10b981';
    hostElement.style.borderRadius = '8px';
    
    // Access shadow DOM elements
    const button = shadowRoot.querySelector('.my-button');
    if (button) {
      button.addEventListener('mouseenter', () => {
        console.log('Button hovered');
      });
    }
    
    // Dynamic content updates
    const timestamp = shadowRoot.querySelector('#timestamp');
    if (timestamp) {
      timestamp.textContent = `Connected at: ${new Date().toLocaleTimeString()}`;
    }
  };

  return (
    <Template 
      shadowrootmode="open" 
      connectedCallback={handleConnected}
    >
      <div>
        <h3>Connected Callback Demo</h3>
        <button className="my-button">Click me!</button>
        <p id="timestamp">Connection time will appear here</p>
      </div>
    </Template>
  );
}

Important Notes

Browser Compatibility

  • Shadow DOM: Supported in all modern browsers (Chrome 53+, Firefox 63+, Safari 10+)
  • Declarative Shadow DOM: Limited support - mainly Chrome 90+
  • Adopted Stylesheets: Chrome 73+, Firefox 101+, Safari 16.4+

Behavior

  1. Remounting: The component automatically remounts when key props change to ensure Shadow DOM is recreated properly
  2. Style Isolation: Styles inside Shadow DOM don't affect the parent document and vice versa
  3. Event Handling: Events work normally, with optional focus delegation
  4. Slot Assignment: The component uses named slot assignment by default

Performance Considerations

  • Shadow DOM creation has a small overhead
  • Adopted stylesheets are more performant than inline styles
  • The component handles cleanup automatically to prevent memory leaks

License

This project is licensed under the MIT License - see the LICENSE file for details.