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> </> ); };
Importing
If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.
To import this component from the CDN using a script tag:
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.1.0/cdn/components/mutation-observer/mutation-observer.js"></script>
To import this component from the CDN using a JavaScript import:
import 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.1.0/cdn/components/mutation-observer/mutation-observer.js';
To import this component using a bundler:
import '@shoelace-style/shoelace/dist/components/mutation-observer/mutation-observer.js';
To import this component as a React component:
import SlMutationObserver from '@shoelace-style/shoelace/dist/react/mutation-observer';
Slots
Name | Description |
---|---|
(default) | The content to watch for mutations. |
Learn more about using slots.
Properties
Scroll right to see the entire table
Name | Description | Reflects | Type | Default |
---|---|---|---|---|
attr
|
Watches for changes to attributes. To watch only specific attributes, separate them by a space, e.g.
attr="class id title" . To watch all attributes, use * .
|
|
string
|
- |
attrOldValue
attr-old-value
|
Indicates whether or not the attribute’s previous value should be recorded when monitoring changes. |
|
boolean
|
false
|
charData
char-data
|
Watches for changes to the character data contained within the node. |
|
boolean
|
false
|
charDataOldValue
char-data-old-value
|
Indicates whether or not the previous value of the node’s text should be recorded. |
|
boolean
|
false
|
childList
child-list
|
Watches for the addition or removal of new child nodes. |
|
boolean
|
false
|
disabled
|
Disables the observer. |
|
boolean
|
false
|
updateComplete
|
A read-only promise that resolves when the component has finished updating. |
Learn more about attributes and properties.
Events
Name | React Event | Description | Event Detail |
---|---|---|---|
sl-mutation
|
onSlMutation
|
Emitted when a mutation occurs. |
{ mutationList: MutationRecord[] }
|
Learn more about events.