LLM Reference
LLM Reference: Preview Listener
This is a dense reference for LLMs working with Vextro’s live preview system. The preview listener runs on the public site (inside the iframe) and receives field updates broadcast by the admin panel’s VextroLivePreview sidebar.
Import Path
import { initVextroPreviewListener } from 'vextro/preview';
import type { VextroPreviewEventDetail } from 'vextro/preview';
Types
type VextroPreviewEventDetail = {
data: Record<string, unknown>; // All field values from the admin form
collectionSlug?: string; // Collection the document belongs to
documentId?: string; // ID of the document being previewed
};
// Internal message shape (handled automatically by initVextroPreviewListener)
// _collectionSlug and _id are nested inside data, not top-level
type VextroPreviewMessage = {
type: 'vextro-preview-update';
data: Record<string, unknown>;
};
initVextroPreviewListener(): () => void
Attaches a message event handler to window. Returns a cleanup function that removes the listener.
On each incoming vextro-preview-update message:
- Finds elements with
data-vextro-fieldmatching keys in the data payload - Updates
textContentby default, or updates the attribute named bydata-vextro-attr - Fires a
vextro:preview-dataCustomEventonwindowfor custom handling
The module auto-initializes the listener on import. Do not call initVextroPreviewListener() after any import from vextro/preview — any import (named or side-effect) triggers module-level auto-initialization, and calling the function manually after that registers a second listener.
// Correct: auto-init runs when the module loads
import 'vextro/preview';
The function is exported for environments where ES module side-effects are suppressed (SSR, test runners) and manual initialization is required. In normal browser usage, rely on auto-init.
DOM Attributes
data-vextro-field="<fieldName>"
Marks an element as a preview target. The listener updates textContent with the matching field value.
<h1 data-vextro-field="title">Placeholder</h1>
<p data-vextro-field="excerpt">...</p>
data-vextro-attr="<attrName>"
When present alongside data-vextro-field, the listener updates the named attribute instead of textContent.
<img data-vextro-field="heroImageUrl" data-vextro-attr="src" alt="" />
<a data-vextro-field="ctaUrl" data-vextro-attr="href">Read more</a>
vextro:preview-data Custom Event
Fires on window for every incoming preview message. Use this for fields requiring custom handling (rich text, nested data, arrays).
import type { VextroPreviewEventDetail } from 'vextro/preview';
import { renderTipTapToHtml } from 'vextro/content';
window.addEventListener('vextro:preview-data', (e: CustomEvent<VextroPreviewEventDetail>) => {
const { data, collectionSlug, documentId } = e.detail;
if (data.body) {
document.querySelector('#body').innerHTML = renderTipTapToHtml(data.body);
}
});
Admin Collection Config
Enable the preview panel for a collection by adding a preview option to defineVextroCollection:
export const posts = defineVextroCollection({
slug: 'posts',
preview: {
url: 'https://yoursite.com/posts/{slug}',
},
});
Curly-brace placeholders (e.g. {slug}, {_id}) are replaced with the current document’s field value before the iframe loads.
Security Notes
- The listener accepts messages from any origin (preview may differ from admin domain).
initVextroPreviewListenernever writes data back to Convex or the admin.- Safe to include in production builds — the listener is a no-op when no admin message is received.
- The
vextro:preview-datacustom event detail does not exposeorigin. For origin-restricted environments, add a nativewindow.addEventListener('message', handler)and checkevent.originthere.