Mutation Observer
<sl-mutation-observer> | SlMutationObserver
The Mutation Observer component offers a thin, declarative interface to the
MutationObserver API
.
Examples
Mutation Observer Basics
The mutation observer will report changes to the content it wraps through the
sl-mutation
event. When emitted, a collection of
MutationRecord
objects will be attached to event.detail
that contains information about how it changed.
๐ Click the button and watch the console
<div class="mutation-overview"> <sl-mutation-observer attr="variant"> <sl-button variant="primary">Click to mutate</sl-button> </sl-mutation-observer> <br /> ๐ Click the button and watch the console <script> const container = document.querySelector('.mutation-overview'); const mutationObserver = container.querySelector('sl-mutation-observer'); const button = container.querySelector('sl-button'); const variants = ['primary', 'success', 'neutral', 'warning', 'danger']; let clicks = 0; // Change the button's variant attribute button.addEventListener('click', () => { clicks++; button.setAttribute('variant', variants[clicks % variants.length]); }); // Log mutations mutationObserver.addEventListener('sl-mutation', event => { console.log(event.detail); }); </script> <style> .mutation-overview sl-button { margin-bottom: 1rem; } </style> </div>
.mutation-overview sl-mutation-observer attr="variant" sl-button variant="primary" | Click to mutate br | ๐ Click the button and watch the console javascript: const container = document.querySelector('.mutation-overview'); const mutationObserver = container.querySelector('sl-mutation-observer'); const button = container.querySelector('sl-button'); const variants = ['primary', 'success', 'neutral', 'warning', 'danger']; let clicks = 0; // Change the button's variant attribute button.addEventListener('click', () => { clicks++; button.setAttribute('variant', variants[clicks % variants.length]); }); // Log mutations mutationObserver.addEventListener('sl-mutation', event => { console.log(event.detail); }); css: .mutation-overview sl-button { margin-bottom: 1rem; }
import { useState } from 'react'; import SlButton from '@teamshares/shoelace/dist/react/button'; import SlMutationObserver from '@teamshares/shoelace/dist/react/mutation-observer'; const css = ` .resize-observer-overview div { display: flex; border: solid 2px var(--sl-input-border-color); align-items: center; justify-content: center; text-align: center; padding: 4rem 2rem; } `; const variants = ['primary', 'success', 'neutral', 'warning', 'danger']; let clicks = 0; const App = () => { const [variant, setVariant] = useState('primary'); function handleClick() { clicks++; setVariant(variants[clicks % variants.length]); } return ( <> <SlMutationObserver attr="*" onSlMutation={event => console.log(event.detail)}> <SlButton variant={variant} onClick={handleClick}> Click to mutate </SlButton> </SlMutationObserver> <style>{css}</style> </> ); };
When you create a mutation observer, you must indicate what changes it should respond to by including at
least one of attr
, child-list
, or char-data
. If you donโt specify
at least one of these attributes, no mutation events will be emitted.
Child List
Use the child-list
attribute to watch for new child elements that are added or removed.
<div class="mutation-child-list"> <sl-mutation-observer child-list> <div class="buttons"> <sl-button variant="primary">Add button</sl-button> </div> </sl-mutation-observer> ๐ Add and remove buttons and watch the console <script> const container = document.querySelector('.mutation-child-list'); const mutationObserver = container.querySelector('sl-mutation-observer'); const buttons = container.querySelector('.buttons'); const button = container.querySelector('sl-button[variant="primary"]'); let i = 0; // Add a button button.addEventListener('click', () => { const button = document.createElement('sl-button'); button.textContent = ++i; buttons.append(button); }); // Remove a button buttons.addEventListener('click', event => { const target = event.target.closest('sl-button:not([variant="primary"])'); event.stopPropagation(); if (target) { target.remove(); } }); // Log mutations mutationObserver.addEventListener('sl-mutation', event => { console.log(event.detail); }); </script> <style> .mutation-child-list .buttons { display: flex; gap: 0.25rem; flex-wrap: wrap; margin-bottom: 1rem; } </style> </div>
.mutation-child-list sl-mutation-observer child-list="true" .buttons sl-button variant="primary" | Add button javascript: const container = document.querySelector('.mutation-child-list'); const mutationObserver = container.querySelector('sl-mutation-observer'); const buttons = container.querySelector('.buttons'); const button = container.querySelector('sl-button[variant="primary"]'); let i = 0; // Add a button button.addEventListener('click', () => { const button = document.createElement('sl-button'); button.textContent = ++i; buttons.append(button); }); // Remove a button buttons.addEventListener('click', event => { const target = event.target.closest('sl-button:not([variant="primary"])'); event.stopPropagation(); if (target) { target.remove(); } }); // Log mutations mutationObserver.addEventListener('sl-mutation', event => { console.log(event.detail); }); css: .mutation-child-list .buttons { display: flex; gap: 0.25rem; flex-wrap: wrap; margin-bottom: 1rem; }
import { useState } from 'react'; import SlButton from '@teamshares/shoelace/dist/react/button'; import SlMutationObserver from '@teamshares/shoelace/dist/react/mutation-observer'; const css = ` .mutation-child-list .buttons { display: flex; gap: .25rem; flex-wrap: wrap; margin-bottom: 1rem; } `; let buttonCount = 0; const App = () => { const [buttonIds, setButtonIds] = useState([]); function addButton() { setButtonIds([...buttonIds, ++buttonCount]); } function removeButton(id) { setButtonIds(buttonIds.filter(i => i !== id)); } return ( <> <div className="mutation-child-list"> <SlMutationObserver child-list onSlMutation={event => console.log(event.detail)}> <div className="buttons"> <SlButton variant="primary" onClick={addButton}> Add button </SlButton> {buttonIds.map(id => ( <SlButton key={id} variant="default" onClick={() => removeButton(id)}> {id} </SlButton> ))} </div> </SlMutationObserver> </div> ๐ Add and remove buttons and watch the console <style>{css}</style> </> ); };
Component Props
Property | Default | Details |
---|---|---|
attr
|
โ |
Watches for changes to attributes. To watch only specific attributes, separate them by a space,
e.g. |
attrOldValue
attr-old-value
|
false
|
Indicates whether or not the attributeโs previous value should be recorded when monitoring changes. |
charData
char-data
|
false
|
Watches for changes to the character data contained within the node. |
charDataOldValue
char-data-old-value
|
false
|
Indicates whether or not the previous value of the nodeโs text should be recorded. |
childList
child-list
|
false
|
Watches for the addition or removal of new child nodes. |
disabled
|
false
|
Disables the observer. |
updateComplete
|
A read-only promise that resolves when the component has finished updating. |
Learn more about attributes and properties.
Slots
Name | Details |
---|---|
(default) | The content to watch for mutations. |
Learn more about using slots.
Events
Name | Name | React Event | Details | |
---|---|---|---|---|
sl-mutation
|
sl-mutation
|
onSlMutation
|
Emitted when a mutation occurs. |
Learn more about events.