JSFiddle - React, Tailwind, and code Playground

HTML

<main>
	<my-paragraph>
		Lorem ispum sit amet dolor
	</my-paragraph>
	
	<hr />
	
	<labeled-input>
		This is the form label
	</labeled-input>
</main>

<!-- Template for the MyParagraphElement class -->
<template id="my-paragraph">
	<style>
		section {
			background-color: #fde7fc;
			padding: 5px;
		}
	</style>
	
	<section>
		<h3>Example Header</h3>
		<div>	
			<slot>Ambulance is on its way</slot>
		</div>
		<button>
			Click Me
		</button>
	</section>
</template>

<!-- Template for the LabeledInputElement class -->
<template id="labeled-input">
	<label>
		<div><slot></slot></div>
		<input type="text" />
	</label>
</template>

JavaScript

/**
 * Base class for our shadow elements
 */
class CustomHtmlElement extends HTMLElement 
{	
	/**
	 * Optional template element. If one is not supplied, we
	 * will try to infer one based on the classname.
	 *
	 * @param HTMLElement template
	 * @return void
	 */
	static attach(template) {
		if (!template) {
			const tagName = this.name
				.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
				.toLowerCase()
				.replace(/-?element/, '');
				
			template = document.querySelector(`#${tagName}`);
		}
	
		// Save template reference
		this.template = template;
		
		// Create shadow object
		customElements.define(this.template.id, this);
	}
	
	/**
	 * @return void
	 */
    constructor() {
		super();
		
		// Clone element from our template
		this.templateNode = this.constructor.template.content.cloneNode(true);
		
		// Make shadow
		this.attachShadow({ mode: 'open' }).appendChild(this.templateNode);
			
		// Attach events call
		this.attachEvents();
	}
	
	/**
	 * @return void
	 */
	attachEvents() {
		// Not implemented
	}
	
	/**
	 * @return void
	 */
	detachEvents() {
		// Not implemented
	}
}

/**
 * Custom element class extends our root class
 *
 * @extends CustomHtmlElement
 */
class MyParagraphElement extends CustomHtmlElement {
	/**
	 * Attach events to the DOM
	 *
	 * @return void
	 */
	attachEvents() {
		this.shadowRoot
			.querySelector('button')
			.addEventListener('click', this.Handle_OnClickButton);
	}
	
	/**
	 * Respond to click events
	 * 
	 * @param MouseEvent e
	 * @return void
	 */
	Handle_OnClickButton(e) {
		alert('This button has been clicked');
	}
}

/**
 * Basic labeled input
 *
 * @extends CustomHtmlElement
 */
class LabeledInputElement extends CustomHtmlElement {
    // Not implemented
}


// -------------------------------------------------------------------------

// We could explicitly pass in an element
// const element = document.querySelector('#my-paragraph');
// MyParagraphElement.attach(element);

// Or we could derive it frmo the class name
//...