Overview

onParent(targetRef, events) is an element directive placed on a child (or descendant). It attaches listeners to the element held by targetRef (typically a parent/ancestor set with setRef).

Listeners bind when the ref’s element becomes available, re-sync when the event map updates, and unbind when the host element disconnects.

onParent vs @event vs on()

API
Listener target
Notes
@click=${fn} Same element Native lit-html listener on the host node.
onParent(ref, map) Ref’d ancestor Child hosts the directive; events fire on the parent/ancestor element.
Component on(…) hooks Window / document / … Outer-function lifecycle hooks — different layer.

Child listening to parent scroll

The scroll container owns a ref. Each row applies onParent(scrollRef, { scroll, click }) so listeners attach to the parent and clean up with the row.

import { html, atom, ref, setRef, onParent, renderApp } from 'mates';

const App = () => {
const scrollRef = ref();
const scrollTop = atom(0);
const clicks = atom(0);

return () => html`
<div class="m-col m-gap">
<p class="label m-0">
scrollTop: ${scrollTop()}px · parent clicks: ${clicks()}
</p>
<div
${setRef(scrollRef)}
class="p-20"
>
<div
${onParent(scrollRef, {
scroll: (e) => scrollTop.set(Math.round(e.target.scrollTop)),
click: () => clicks.set(n => n + 1),
})}
>
${Array.from({ length: 8 }, (_, i) => html`
<div class="card card-body m-b-10">
Row ${i + 1} — scroll/click listeners are on the parent via onParent
</div>
`)}
</div>
</div>
</div>
`;
};
renderApp(App, document.getElementById('app'));

Parent click counter

Listen for click on an ancestor ref from a nested child.

import { html, atom, ref, setRef, onParent, renderApp } from 'mates';

const App = () => {
const wrap = ref();
const n = atom(0);
return () => html`
<div class="m-col m-gap">
<div ${setRef(wrap)} class="card card-body">
<p class="label m-0">Parent clicks: ${n()}</p>
<div ${onParent(wrap, { click: () => n.set(c => c + 1) })}>
<button class="btn-ghost">Click inside (bubbles to parent)</button>
</div>
</div>
</div>
`;
};
renderApp(App, document.getElementById('app'));