useMutationObserver
Attach a MutationObserver to an element ref. The observer is created when the ref resolves, disconnected when the ref changes or the component scope is disposed, and re-attached automatically when the ref points at a new element.
Demo
data-state = "idle"
0 mutations observed
<script setup lang="ts">
import { ref, useTemplateRef } from 'vue';
import { useMutationObserver } from '@basmilius/common';
const target = useTemplateRef<HTMLDivElement>('target');
const state = ref('idle');
const mutations = ref(0);
useMutationObserver(target, () => {
mutations.value++;
}, {
attributes: true,
attributeFilter: ['data-state']
});
function toggle(): void {
state.value = state.value === 'idle' ? 'active' : 'idle';
}
</script>
<template>
<div class="demo">
<div ref="target" class="target" :data-state="state">
data-state = "{{ state }}"
</div>
<div class="actions">
<button @click="toggle">Toggle attribute</button>
<span class="count">{{ mutations }} mutations observed</span>
</div>
</div>
</template>
<style scoped>
.demo {
padding: 24px;
border: 1px solid var(--vp-c-border);
border-radius: 12px;
background: var(--vp-c-bg-soft);
}
.target {
padding: 16px;
margin-bottom: 16px;
border-radius: 8px;
background: var(--vp-c-bg);
box-shadow: 0 0 0 1px var(--vp-c-border) inset;
font-family: var(--vp-font-family-mono);
font-size: 14px;
color: var(--vp-c-text-2);
transition: box-shadow .2s, color .2s;
}
.target[data-state='active'] {
box-shadow: 0 0 0 2px var(--vp-c-brand-1) inset;
color: var(--vp-c-brand-1);
}
.actions {
display: flex;
align-items: center;
gap: 14px;
}
.actions button {
padding: 8px 16px;
border-radius: 8px;
background: var(--vp-c-brand-1);
font-weight: 600;
color: var(--vp-c-white);
}
.count {
font-family: var(--vp-font-family-mono);
font-size: 13px;
color: var(--vp-c-text-3);
}
</style>Importing
ts
import { useMutationObserver } from '@basmilius/common';Usage
vue
<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { useMutationObserver } from '@basmilius/common';
const target = useTemplateRef<HTMLDivElement>('target');
useMutationObserver(target, mutations => {
for (const mutation of mutations) {
console.log('mutation', mutation);
}
}, {
attributes: true,
attributeFilter: ['data-state']
});
</script>
<template>
<div ref="target" data-state="idle">Watch me</div>
</template>The string passed to useTemplateRef must match the ref="…" attribute on the template node. The returned ShallowRef is null until the component mounts.
When options is omitted, the observer is created with { attributes: true }. Component refs are unwrapped via unwrapElement, so passing a component instance ref works as well.
Type signature
ts
type EligibleElement = HTMLElement | ComponentPublicInstance;
declare function useMutationObserver<TElement extends EligibleElement>(
elementRef: Ref<TElement | null>,
callback: MutationCallback,
options?: MutationObserverInit
): void;