Skip to content

Mutation Observer

<quiet-mutation-observer> stable since 1.0

Mutation observers watch child elements and dispatch an event when they mutate.

The component uses a MutationObserver to monitor when its direct children are added, removed, or modified. A quiet-mutation event is dispatched for each observed change, providing detailed information about what was mutated.

The component is styled with display: contents , allowing you to easily apply flex and grid layouts to the containing element without the component interfering.

1
2
3
Add box Add and remove some items, then open the console to inspect the output.
<div id="mutation__overview">
  <quiet-mutation-observer child-list>
    <div class="box">1 <button aria-label="Remove"></button></div>
    <div class="box">2 <button aria-label="Remove"></button></div>
    <div class="box">3 <button aria-label="Remove"></button></div>
  </quiet-mutation-observer>
</div>

<quiet-button>Add box</quiet-button>

<small>Add and remove some items, then open the console to inspect the output.</small>

<script>
  const container = document.getElementById('mutation__overview');
  const mutationObserver = container.querySelector('quiet-mutation-observer');
  const appendButton = container.nextElementSibling;
  let count = mutationObserver.querySelectorAll('.box').length;

  // Listen for mutations
  mutationObserver.addEventListener('quiet-mutation', event => {
    console.log(event.detail.record);
  });

  // Remove a card
  mutationObserver.addEventListener('click', event => {
    const button = event.target.closest('button');
    const box = button?.closest('.box');
    box?.remove();
  });

  // Append a box
  appendButton.addEventListener('click', () => {
    const html = `<div class="box">${++count} <button aria-label="Remove">✕</button></div>`;
    mutationObserver.insertAdjacentHTML('beforeEnd', html);
  });
</script>

<style>
  #mutation__overview {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    min-height: 5rem;
    margin-block-end: 1rem;

    .box {
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
      min-width: 5rem;
      height: 5rem;
      border-radius: var(--quiet-border-radius);
      background-color: var(--quiet-neutral-fill-softer);
      box-shadow: var(--quiet-shadow-softer);
      text-align: center;
      padding: 1rem;

      button {
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: var(--quiet-neutral-fill-loud);
        color: var(--quiet-neutral-text-on-loud);
        font-size: .75em;
        padding: 0;
        width: 1.25rem;
        height: 1.25rem;
        min-height: 0;
        position: absolute;
        top: -0.625rem;
        right: -0.625rem;
        border-radius: 50%;
      }
    }

    ~ small {
      display: block;
      margin-block-start: 1rem;
    }
  }
</style>

Remember that only direct children of the host element are observed. Nested elements will not trigger mutation events unless the subtree attribute is enabled.

Examples Jump to heading

Providing content Jump to heading

Slot one or more elements into the mutation observer and listen for the quiet-mutation event. The event includes event.detail.record, which is a MutationRecord object that corresponds to the mutated element.

In its simplest form, a mutation observer can be used like this.

<quiet-mutation-observer child-list>
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</quiet-mutation-observer>

<script>
  const mutationObserver = document.querySelector('quiet-mutation-observer');

  // Listen for mutations
  mutationObserver.addEventListener('quiet-mutation', event => {
    console.log(event.detail.record); // MutationRecord
  });
</script>

Observing attribute changes Jump to heading

Use the attr attribute to monitor changes to element attributes. You can optionally specify attr-old-value to record the previous attribute value.

<quiet-mutation-observer attr attr-old-value>
  <div id="target" class="example">Watch my attributes</div>
</quiet-mutation-observer>

<script>
  const observer = document.querySelector('quiet-mutation-observer');
  const target = observer.querySelector('#target');

  observer.addEventListener('quiet-mutation', event => {
    const record = event.detail.record;
    console.log(`Attribute "${record.attributeName}" changed`);
    console.log(`Old value: ${record.oldValue}`);
    console.log(`New value: ${record.target.getAttribute(record.attributeName)}`);
  });

  // Change an attribute to trigger the observer
  target.className = 'modified';
</script>

Filtering specific attributes Jump to heading

Limit observations to specific attributes using the attr-filter attribute. Separate multiple attribute names with spaces.

<quiet-mutation-observer attr attr-filter="class data-state">
  <div class="example" data-state="active" id="example">
    Only class and data-state changes are observed
  </div>
</quiet-mutation-observer>

<script>
  const observer = document.querySelector('quiet-mutation-observer');
  const target = observer.querySelector('#example');

  observer.addEventListener('quiet-mutation', event => {
    console.log(`Observed attribute: ${event.detail.record.attributeName}`);
  });

  // These will trigger events
  target.className = 'modified';
  target.setAttribute('data-state', 'inactive');

  // This will NOT trigger an event
  target.id = 'new-id';
</script>

Observing text content changes Jump to heading

Use the character-data attribute to monitor changes to text nodes. The character-data-old-value attribute records the previous text content.

<quiet-mutation-observer character-data character-data-old-value subtree>
  <p id="text-content">Original text content</p>
</quiet-mutation-observer>

<script>
  const observer = document.querySelector('quiet-mutation-observer');
  const paragraph = observer.querySelector('#text-content');

  observer.addEventListener('quiet-mutation', event => {
    const record = event.detail.record;
    console.log(`Text changed from "${record.oldValue}" to "${record.target.textContent}"`);
  });

  // Change text content to trigger the observer
  paragraph.textContent = 'Updated text content';
</script>

Observing nested elements Jump to heading

By default, only direct children are observed. Add the subtree attribute to observe changes in nested elements as well.

<quiet-mutation-observer child-list subtree>
  <div class="container">
    <div class="nested">
      <span>Nested content</span>
    </div>
  </div>
</quiet-mutation-observer>

<script>
  const observer = document.querySelector('quiet-mutation-observer');
  const nested = observer.querySelector('.nested');

  observer.addEventListener('quiet-mutation', event => {
    console.log('Mutation detected in subtree:', event.detail.record);
  });

  // This will trigger the observer even though span is deeply nested
  nested.innerHTML = '<span>New nested content</span>';
</script>

Combining multiple observation types Jump to heading

You can observe multiple types of mutations simultaneously by combining attributes.

<quiet-mutation-observer 
  child-list 
  attr 
  character-data 
  subtree 
  attr-old-value 
  character-data-old-value
>
  <div class="comprehensive-example">
    <p>This observer watches everything</p>
  </div>
</quiet-mutation-observer>

<script>
  const observer = document.querySelector('quiet-mutation-observer');

  observer.addEventListener('quiet-mutation', event => {
    const record = event.detail.record;
    
    switch (record.type) {
      case 'childList':
        console.log('Child nodes changed');
        break;
      case 'attributes':
        console.log(`Attribute "${record.attributeName}" changed`);
        break;
      case 'characterData':
        console.log('Text content changed');
        break;
    }
  });
</script>

Disabling the observer Jump to heading

Use the disabled attribute to temporarily stop observing mutations without removing the component.

<quiet-mutation-observer child-list disabled>
  <div>Changes to this content won't be observed</div>
</quiet-mutation-observer>

<script>
  const observer = document.querySelector('quiet-mutation-observer');

  // Re-enable observation
  observer.disabled = false;

  // Disable observation again
  observer.disabled = true;
</script>

API Jump to heading

Importing Jump to heading

The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.

CDN npm

To manually import <quiet-mutation-observer> from the CDN, use the following code.

import 'https://cdn.jsdelivr.net/npm/@quietui/quiet-browser@1.0.0/dist/components/mutation-observer/mutation-observer.js';

To manually import <quiet-mutation-observer> from npm, use the following code.

import '@quietui/quiet/dist/components/mutation-observer/mutation-observer.js';

Slots Jump to heading

Mutation Observer supports the following slots. Learn more about using slots

Name Description
(default) The elements to observe. All direct children of the host element are observed, but not nested elements.

Properties Jump to heading

Mutation Observer has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties

Property / Attribute Description Reflects Type Default
disabled Disables the mutation observer. boolean false
attr Indicates whether attributes should be observed. boolean false
attrOldValue
attr-old-value
Indicates whether attribute old value should be recorded. boolean false
attrFilter
attr-filter
One or more attributes to limit observations to, separate by a space. When not specified, all attributes are observed. string ''
childList
child-list
Indicates whether mutations to target's children are to be observed. boolean false
subtree Indicates whether mutations to target's descendants are to be observed. boolean false
characterData
character-data
Indicates whether character data should be observed. boolean false
characterDataOldValue
character-data-old-value
Indicates whether character data old value should be recorded. boolean false

Events Jump to heading

Mutation Observer dispatches the following custom events. You can listen to them the same way was native events. Learn more about custom events

Name Description
quiet-mutation Emitted when a slotted element is mutated. The event.detail.record property contains a MutationRecord with information about the mutation.
Search this website Toggle dark mode Get the code on GitHub Follow @quietui.org on Bluesky Follow @quiet_ui on X

    No results found