Learn about Shadow DOM encapsulation and scoped styles
These user cards use Shadow DOM for style encapsulation:
class UserCard extends HTMLElement {
constructor() {
super();
// Attach shadow DOM for encapsulation
this.attachShadow({ mode: 'open' });
}
// Observed attributes for reactivity
static get observedAttributes() {
return ['name', 'role', 'avatar'];
}
connectedCallback() {
this.render();
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
this.render();
}
}
render() {
this.shadowRoot.innerHTML = `
<style>
.card {
display: flex;
align-items: center;
gap: 1rem;
padding: 1.5rem;
background: white;
border-radius: 0;
border: 1px solid #e8e3db;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.avatar {
width: 64px;
height: 64px;
border-radius: 0;
border: 3px solid #2d1b69;
}
.name {
font-size: 1.25rem;
font-weight: 600;
margin: 0;
}
</style>
<div class="card">
<img class="avatar" src="\${this.getAttribute('avatar')}">
<div class="info">
<h3 class="name">\${this.getAttribute('name')}</h3>
<p class="role">\${this.getAttribute('role')}</p>
</div>
</div>
`;
}
}
customElements.define('user-card', UserCard);
<user-card
name="Sarah Johnson"
role="Frontend Developer"
avatar="https://ui-avatars.com/api/?name=Sarah+Johnson">
</user-card>
Open the browser console and type:
const card = document.querySelector('user-card');
card.setAttribute('name', 'Your Name');
card.setAttribute('role', 'Your Role');