diff --git a/packages/core/src/canvas/config/config.ts b/packages/core/src/canvas/config/config.ts
index 8bd45e009..de374e03a 100644
--- a/packages/core/src/canvas/config/config.ts
+++ b/packages/core/src/canvas/config/config.ts
@@ -1,5 +1,9 @@
import Component from '../../dom_components/model/Component';
+import ComponentView from '../../dom_components/view/ComponentView';
+import Editor from '../../editor';
import { CanvasSpotBuiltInTypes } from '../model/CanvasSpot';
+import Frame from '../model/Frame';
+import FrameView from '../view/FrameView';
export interface CanvasConfig {
stylePrefix?: string;
@@ -102,6 +106,19 @@ export interface CanvasConfig {
* @default false
*/
scrollableCanvas?: boolean;
+
+ /**
+ * Custom renderer function for canvas content.
+ * This allows replacing the default HTML rendering with custom frameworks like React.
+ * @example
+ * customRenderer: ({ editor, frame, window, frameView }) => {
+ * // Mount React on the frame body
+ * const root = frame.getComponent();
+ * const reactRoot = createRoot(window.document.body);
+ * reactRoot.render();
+ * }
+ */
+ customRenderer?: (options: { editor: Editor; frame: Frame; window: Window; frameView: FrameView }) => ComponentView;
}
const config: () => CanvasConfig = () => ({
diff --git a/packages/core/src/canvas/view/FrameView.ts b/packages/core/src/canvas/view/FrameView.ts
index c987aeb7b..7eb88d3c3 100644
--- a/packages/core/src/canvas/view/FrameView.ts
+++ b/packages/core/src/canvas/view/FrameView.ts
@@ -429,14 +429,23 @@ export default class FrameView extends ModuleView {
const { view } = em?.Components?.getType('wrapper') || {};
if (!view) return;
- this.wrapper = new view({
- model: root,
- config: {
- ...root.config,
- em,
+ if (typeof config.customRenderer === 'function') {
+ this.wrapper = config.customRenderer({
+ editor: em.Editor,
+ frame: model,
+ window: win,
frameView: this,
- },
- }).render();
+ });
+ } else {
+ this.wrapper = new view({
+ model: root,
+ config: {
+ ...root.config,
+ em,
+ frameView: this,
+ },
+ }).render();
+ }
append(body, this.wrapper?.el!);
append(
body,