Custom Events
Editframe elements dispatch custom events to enable interactive UI components. Events follow the DOM event bubbling model with bubbles: true and composed: true to traverse shadow DOM boundaries.
Event Categories
Transform & Manipulation Events
Events fired during user interactions with transform handles, trim controls, and resize operations.
trim-change
Fired by ef-trim-handles when trim handles are dragged. Use this to update element trim values in real-time.
interface TrimChangeDetail {elementId: string;type: "start" | "end" | "region";value: TrimValue;}interface TrimValue {startMs: number;endMs: number;}
Example: Listen to trim changes
bounds-change
Fired by ef-transform-handles and ef-resizable-box when element bounds change through user interaction.
interface TransformBounds {x: number;y: number;width: number;height: number;rotation?: number;}
Example: Listen to bounds changes
<ef-transform-handles.bounds=${{ x: 100, y: 100, width: 200, height: 150 }}enable-rotation></ef-transform-handles><script>document.querySelector('ef-transform-handles').addEventListener('bounds-change', (e) => {const { bounds } = e.detail;console.log('New bounds:', bounds);// Update target element position/sizetargetElement.style.left = `${bounds.x}px`;targetElement.style.top = `${bounds.y}px`;targetElement.style.width = `${bounds.width}px`;targetElement.style.height = `${bounds.height}px`;});</script>
rotation-change
Fired by ef-transform-handles when the rotation handle is dragged. Provides the new rotation value in degrees.
interface RotationChangeDetail {rotation: number; // Degrees (0-360)}
change (dial)
Fired by ef-dial when the dial value changes through user interaction. Provides the new angle value.
interface DialChangeDetail {value: number; // Degrees (0-360)}
Example: Dial with rotation control
<ef-dial value="45"></ef-dial><script>document.querySelector('ef-dial').addEventListener('change', (e) => {const { value } = e.detail;console.log('Dial rotation:', value, '°');// Apply rotation to elementtargetElement.style.transform = `rotate(${value}deg)`;});</script>
Timeline & Playback Events
Events fired during timeline scrubbing, track manipulation, and playback control.
seek
Fired by ef-scrubber when the playhead position changes. Detail contains the new time in milliseconds.
<ef-scrubber target="composition"></ef-scrubber><script>document.querySelector('ef-scrubber').addEventListener('seek', (e) => {const timeMs = e.detail;console.log('Seek to:', timeMs, 'ms');});</script>
scrub-segment-loading
Fired by ef-video during scrub track loading to provide progress feedback for UI loading indicators.
interface ScrubSegmentLoadingDetail {segmentId: number;timeRangeMs: [number, number];loaded: number;total: number;status: "loading" | "loaded";}
Example: Show loading progress
<ef-video id="myVideo" src="..."></ef-video><div id="progress" style="display: none;">Loading scrub preview...</div><script>document.getElementById('myVideo').addEventListener('scrub-segment-loading', (e) => {const { loaded, total, status } = e.detail;const progressEl = document.getElementById('progress');if (status === 'loading') {progressEl.style.display = 'block';progressEl.textContent = `Loading ${loaded}/${total}...`;} else {progressEl.style.display = 'none';}});</script>
row-select
Fired by ef-timeline-row when a timeline row is clicked. Used to coordinate selection between timeline and canvas.
interface RowSelectDetail {elementId: string;element: Element;}
row-hover
Fired by ef-timeline-row when mouse enters or leaves a row. Useful for highlighting elements in the preview during timeline hover.
interface RowHoverDetail {element: Element | null; // null when mouse leaves}
track-trim-change
Fired by timeline track items when their trim handles change. Bubbles up from the track item to the timeline.
Selection & Hierarchy Events
Events fired when users interact with hierarchy panels, layer lists, or canvas selection tools.
hierarchy-select
Fired by ef-hierarchy when an element is selected in the hierarchy panel. Typically used to sync selection with canvas or preview.
interface HierarchySelectDetail {elementId: string;}
Example: Sync hierarchy selection with canvas
<ef-hierarchy target="composition"></ef-hierarchy><script>document.querySelector('ef-hierarchy').addEventListener('hierarchy-select', (e) => {const { elementId } = e.detail;// Update canvas selectionconst canvas = document.querySelector('ef-canvas');const element = document.getElementById(elementId);if (element) {canvas.selectElement(element);}});</script>
hierarchy-reorder
Fired by ef-hierarchy when elements are reordered via drag and drop. Use this to update the DOM structure.
interface HierarchyReorderDetail {sourceId: string;targetId: string;position: "before" | "after" | "inside";}
Example: Handle reordering
<script>document.querySelector('ef-hierarchy').addEventListener('hierarchy-reorder', (e) => {const { sourceId, targetId, position } = e.detail;const source = document.getElementById(sourceId);const target = document.getElementById(targetId);if (position === 'before') {target.parentElement.insertBefore(source, target);} else if (position === 'after') {target.parentElement.insertBefore(source, target.nextSibling);} else if (position === 'inside') {target.appendChild(source);}});</script>
tree-select
Fired by ef-tree when a tree item is selected. Generic tree selection event for tree-based UI components.
interface TreeSelectDetail {id: string;item: any;}
selectionchange
Fired by canvas SelectionModel when the set of selected elements changes through user interaction.
interface SelectionChangeDetail {selection: Set<Element>;}
Temporal & Content Events
Events fired by temporal elements during initialization, content changes, and state transitions.
readystatechange
Fired by temporal elements (ef-timegroup, ef-video, ef-audio, etc.) when their ready state changes during initialization.
interface ReadyStateChangeDetail {readyState: string; // e.g., "loading", "interactive", "complete"}
contentchange
Fired by temporal elements when their content structure changes (children added/removed, attributes modified).
child-duration-changed
Fired by media elements when a child element's duration changes, triggering recalculation of parent duration.
interface ChildDurationChangedDetail {duration: number;}
activeroottemporalchange
Fired by ef-canvas when the active root temporal element changes. Used to coordinate timeline and canvas state.
interface ActiveRootTemporalChangeDetail {activeRootTemporal: Element | null;}
Event Handling Patterns
Bubbling and Composed
All custom events are dispatched with bubbles: true and composed: true, allowing them to traverse shadow DOM boundaries and be caught by ancestor elements.
<div id="app"><ef-timeline><ef-timeline-row><!-- Events bubble up from here --></ef-timeline-row></ef-timeline></div><script>// Can listen at any ancestor leveldocument.getElementById('app').addEventListener('row-select', (e) => {console.log('Row selected:', e.detail.elementId);});</script>
TypeScript Event Types
Import event detail types for type-safe event handling:
import type { TrimChangeDetail, DialChangeDetail } from "@editframe/elements";element.addEventListener("trim-change", (e: CustomEvent<TrimChangeDetail>) => {const { type, value } = e.detail;// TypeScript knows the shape of e.detail});
Event Coordination
Many events are designed to work together for coordinated UI updates:
// Coordinate timeline selection with canvashierarchy.addEventListener('hierarchy-select', (e) => {const element = document.getElementById(e.detail.elementId);canvas.selectElement(element);});// Coordinate canvas selection with transform handlescanvas.addEventListener('selectionchange', (e) => {const selected = Array.from(e.detail.selection)[0];if (selected) {transformHandles.bounds = getBoundsFromElement(selected);}});
Related
- Trim Handles - Trim handle component
- Transform Handles - Transform handle component
- Dial - Rotary dial input
- Hierarchy - Hierarchy panel component
- Timeline - Timeline editor component