Controls
The <ef-controls>
element is a context bridge that allows you to control an <ef-preview>
or <ef-workbench>
element from anywhere in your application, even when they're not direct ancestors. It proxies playback state, timing information, and other contexts from a target element to its children.
Basic Usage
<ef-preview id="my-preview">
<ef-timegroup slot="canvas" mode="contain" className="w-[1920px] h-[1080px]">
<ef-video src="/assets/video.mp4"></ef-video>
</ef-timegroup>
</ef-preview>
<!-- Controls can be placed anywhere, not inside the preview -->
<ef-controls target="my-preview">
<ef-toggle-play>
<button slot="play">Play</button>
<button slot="pause">Pause</button>
</ef-toggle-play>
<ef-scrubber></ef-scrubber>
<ef-time-display></ef-time-display>
</ef-controls>
How Context Bridging Works
Normally, control elements like <ef-scrubber>
and <ef-toggle-play>
need to be descendants of an <ef-preview>
or <ef-workbench>
to access playback context. The <ef-controls>
element solves this by:
- Finding the target element by its ID
- Subscribing to all relevant contexts from that target
- Re-providing those contexts to its own children
- Keeping all contexts synchronized in real-time
This enables flexible UI layouts where controls can be positioned independently of the video preview.
Learn More: For a detailed explanation of how the target system works and what temporal elements are, see Understanding Temporal Elements.
Attributes
target
string
The ID of the element to control, typically an <ef-preview>
or <ef-workbench>
.
The controls element will look for an element with this ID in the document and bridge its context to child elements.
Example:
<ef-preview id="main-preview">...</ef-preview>
<ef-controls target="main-preview">...</ef-controls>
Proxied Contexts
The <ef-controls>
element automatically bridges the following contexts from the target element:
| Context | Type | Description |
|---------|------|-------------|
| playing | boolean
| Whether the video is currently playing |
| loop | boolean
| Whether the video should loop on completion |
| currentTimeMs | number
| Current playback time in milliseconds |
| durationMs | number
| Total duration in milliseconds |
| targetTimegroup | EFTimegroup
| Reference to the root timegroup |
| focusedElement | HTMLElement
| Currently focused element for editing |
| focusContext | FocusContext
| Focus management context |
Child elements of <ef-controls>
can read and write to these contexts as if they were direct children of the target element.
Examples
Remote Control Panel
Create a separate control panel that can be positioned anywhere:
<div className="layout">
<div className="preview-area">
<ef-preview id="editor-preview">
<ef-timegroup slot="canvas" mode="contain" className="w-[1920px] h-[1080px]">
<ef-video src="/video.mp4"></ef-video>
</ef-timegroup>
</ef-preview>
</div>
<div className="control-panel">
<ef-controls target="editor-preview">
<div className="flex flex-col gap-4 p-4 bg-gray-800 rounded">
<h3 className="text-white">Playback Controls</h3>
<div className="flex gap-2">
<ef-toggle-play>
<button className="btn" slot="play">▶ Play</button>
<button className="btn" slot="pause">⏸ Pause</button>
</ef-toggle-play>
<ef-toggle-loop>
<button className="btn">🔁 Loop</button>
</ef-toggle-loop>
</div>
<ef-scrubber></ef-scrubber>
<ef-time-display></ef-time-display>
</div>
</ef-controls>
</div>
</div>
Multiple Control Sets
Control the same preview from multiple locations:
<ef-preview id="video-editor">
<!-- Video content -->
</ef-preview>
<!-- Main controls -->
<ef-controls target="video-editor">
<ef-scrubber></ef-scrubber>
<ef-toggle-play>...</ef-toggle-play>
</ef-controls>
<!-- Secondary controls in a different part of the UI -->
<ef-controls target="video-editor">
<ef-time-display></ef-time-display>
<ef-toggle-loop>...</ef-toggle-loop>
</ef-controls>
Modal Control Panel
Use controls in a modal or overlay that's outside the normal DOM hierarchy:
<!-- Main video editor -->
<ef-preview id="main-editor">
<ef-timegroup slot="canvas" mode="contain" className="w-[1920px] h-[1080px]">
<ef-video src="/video.mp4"></ef-video>
</ef-timegroup>
</ef-preview>
<!-- Modal rendered at document root -->
<dialog open>
<h2>Playback Settings</h2>
<ef-controls target="main-editor">
<ef-toggle-loop>
<label>
<input type="checkbox" /> Loop playback
</label>
</ef-toggle-loop>
<ef-time-display></ef-time-display>
</ef-controls>
</dialog>
Use Cases
Separated UI Layout
Build layouts where the video preview and controls are in completely different parts of your application:
- Video player in the main content area
- Controls in a sticky footer
- Timeline in a collapsible sidebar
- Settings in a modal dialog
Portal-Based Rendering
When using React portals, Vue teleports, or similar patterns that render content outside the normal component tree, <ef-controls>
maintains the connection to the target element.
Multi-Monitor Editing
Build applications where the video preview is on one screen and the control interface is on another, all controlled through a single set of contexts.
Technical Notes
- Uses Lit's
@lit/context
for efficient context updates - Automatically subscribes to context changes for real-time synchronization
- Renders with
display: block
by default (can be styled with CSS) - Uses
createRenderRoot()
override to render in light DOM - Updates are batched for performance
Limitations
- The target element must have an
id
attribute - The target element must be present in the DOM when controls are initialized
- Context updates flow both ways: children can modify target state
Related Elements
- EFPreview - Preview container that can be controlled
- EFTogglePlay - Playback control for use within ef-controls
- EFToggleLoop - Loop control for use within ef-controls
- EFScrubber - Scrubbing control for use within ef-controls
- EFTimeDisplay - Time display for use within ef-controls