diff --git a/package.json b/package.json
index ff7828f9d7..eeb12ba182 100644
--- a/package.json
+++ b/package.json
@@ -171,6 +171,7 @@
     "draft-js-side-toolbar-plugin": "3.0.1",
     "draftjs-to-html": "0.8.4",
     "element-closest": "2.0.2",
+    "embed-video": "2.0.4",
     "es6-object-assign": "1.1.0",
     "es6-promise": "2.3.0",
     "eventlistener": "0.0.1",
diff --git a/web/client/components/mapviews/settings/CompactRichTextEditor.jsx b/web/client/components/mapviews/settings/CompactRichTextEditor.jsx
new file mode 100644
index 0000000000..5f3acd59bd
--- /dev/null
+++ b/web/client/components/mapviews/settings/CompactRichTextEditor.jsx
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2022, GeoSolutions Sas.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import React from 'react';
+import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
+import { Editor } from 'react-draft-wysiwyg';
+import embed from 'embed-video';
+import { DEFAULT_FONT_FAMILIES } from '../../../utils/GeoStoryUtils';
+
+export const resizeBase64Image = (src, options) => {
+    return new Promise((resolve, reject) => {
+        const {
+            size,
+            type = 'image/png',
+            quality = 0.9
+        } = options || {};
+        const img = new Image();
+        img.crossOrigin = 'anonymous';
+        img.onload = () => {
+            const { naturalWidth, naturalHeight } = img;
+            const imgResolution = naturalWidth / naturalHeight;
+            const width = size;
+            const height = size / imgResolution;
+            const canvas = document.createElement('canvas');
+            canvas.setAttribute('width', width);
+            canvas.setAttribute('height', height);
+            const ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0, width, height);
+            const dataURL = canvas.toDataURL(type, quality);
+            resolve(dataURL);
+        };
+        img.onerror = (error) => {
+            reject(error);
+        };
+        img.src = src;
+    });
+};
+
+function CompactRichTextEditor({
+    wrapperClassName = 'ms-compact-text-editor',
+    toolbarOptions,
+    ...props
+}) {
+
+    return (
+        <Editor
+            {...props}
+            editorStyle={{ minHeight: 200 }}
+            wrapperClassName={wrapperClassName}
+            toolbar={{
+                options: toolbarOptions || ['fontFamily', 'blockType', 'inline', 'textAlign', 'list', 'link', 'colorPicker', 'remove', 'image', 'embedded'],
+                image: {
+                    urlEnabled: true,
+                    // upload controlled via props, disabled by default
+                    uploadEnabled: props.uploadEnabled || false,
+                    alignmentEnabled: false,
+                    uploadCallback: (file) => new Promise((resolve, reject) => {
+                        const reader = new FileReader();
+                        reader.addEventListener('load', () => {
+                            resizeBase64Image(reader.result, {
+                                size: 500,
+                                type: 'image/jpeg',
+                                quality: 0.8
+                            }).then((linkBase64) => {
+                                resolve({ data: { link: linkBase64 } });
+                            });
+                        });
+                        if (file) {
+                            reader.readAsDataURL(file);
+                        } else {
+                            reject();
+                        }
+                    }),
+                    previewImage: true,
+                    inputAccept: 'image/gif,image/jpeg,image/jpg,image/png,image/svg',
+                    alt: props.alt || { present: false, mandatory: false },
+                    defaultSize: {
+                        height: 'auto',
+                        width: '100%'
+                    }
+                },
+                fontFamily: {
+                    // Setup fonts via props or use default from GeoStories
+                    options: props.fonts || DEFAULT_FONT_FAMILIES
+                },
+                link: {
+                    inDropdown: false,
+                    showOpenOptionOnHover: true,
+                    defaultTargetOption: '_self',
+                    options: ['link', 'unlink']
+                },
+                blockType: {
+                    inDropdown: true,
+                    options: ['Normal', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Blockquote', 'Code']
+                },
+                inline: {
+                    inDropdown: true,
+                    options: ['bold', 'italic', 'underline', 'strikethrough', 'monospace']
+                },
+                textAlign: {
+                    inDropdown: true
+                },
+                list: {
+                    inDropdown: true
+                },
+                embedded: {
+                    embedCallback: link => {
+                        const detectedSrc = /<iframe.*? src="(.*?)"/.exec(embed(link));
+                        return (detectedSrc && detectedSrc[1]) || link;
+                    },
+                    defaultSize: {
+                        height: 'auto',
+                        width: '100%'
+                    }
+                }
+            }}
+        />
+    );
+}
+
+export default CompactRichTextEditor;
diff --git a/web/client/components/widgets/builder/wizard/text/TextOptions.jsx b/web/client/components/widgets/builder/wizard/text/TextOptions.jsx
index 3300abe79a..f88bec1a0c 100644
--- a/web/client/components/widgets/builder/wizard/text/TextOptions.jsx
+++ b/web/client/components/widgets/builder/wizard/text/TextOptions.jsx
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright 2018, GeoSolutions Sas.
  * All rights reserved.
  *
@@ -6,34 +6,64 @@
  * LICENSE file in the root directory of this source tree.
  */
 
-import React from 'react';
-import { Col, Form, FormControl, FormGroup } from 'react-bootstrap';
-import ReactQuill from '../../../../../libs/quill/react-quill-suspense';
+import React, { useState } from "react";
+import { Col, Form, FormControl, FormGroup } from "react-bootstrap";
+import localizedProps from "../../../../misc/enhancers/localizedProps";
+import {
+    htmlToDraftJSEditorState,
+    draftJSEditorStateToHtml
+} from "../../../../../utils/EditorUtils";
 
-import localizedProps from '../../../../misc/enhancers/localizedProps';
+import withDebounceOnCallback from "../../../../misc/enhancers/withDebounceOnCallback";
+import CompactRichTextEditor from "../../../../mapviews/settings/CompactRichTextEditor";
 
 const TitleInput = localizedProps("placeholder")(FormControl);
+const DescriptorEditor = withDebounceOnCallback(
+    "onEditorStateChange",
+    "editorState"
+)(CompactRichTextEditor);
 
-const Editor = localizedProps("placeholder")(ReactQuill);
-
-export default ({ data = {}, onChange = () => { }}) => (
-    <div>
-        <Col key="form" xs={12}>
-            <Form>
-                <FormGroup controlId="title">
-                    <Col sm={12}>
-                        <TitleInput style={{ marginBottom: 10 }} placeholder="widgets.builder.wizard.titlePlaceholder" value={data.title} type="text" onChange={e => onChange("title", e.target.value)} />
-                    </Col>
-                </FormGroup>
-            </Form>
-        </Col>
-        <Editor modules={{
-            toolbar: [
-                [{'size': ['small', false, 'large', 'huge'] }, 'bold', 'italic', 'underline', 'blockquote'],
-                [{'list': 'bullet' }, {'align': [] }],
-                [{'color': [] }, {'background': [] }, 'clean'], ['image', 'link']
-            ]
-        }} placeholder="widgets.builder.wizard.textPlaceholder" value={data && data.text || ''} onChange={(val) => onChange("text", val)} />
-    </div>
-);
+function TextOptions({ data = {}, onChange = () => {} }) {
+    const [editorState, setEditorState] = useState(
+        htmlToDraftJSEditorState(data.text || "")
+    );
 
+    return (
+        <div>
+            <Col key="form" xs={12}>
+                <Form>
+                    <FormGroup controlId="title">
+                        <Col sm={12}>
+                            <TitleInput
+                                style={{ marginBottom: 10 }}
+                                placeholder="widgets.builder.wizard.titlePlaceholder"
+                                value={data.title}
+                                type="text"
+                                onChange={(e) =>
+                                    onChange("title", e.target.value)
+                                }
+                            />
+                        </Col>
+                    </FormGroup>
+                </Form>
+            </Col>
+            <DescriptorEditor
+                editorState={editorState}
+                onEditorStateChange={(newEditorState) => {
+                    const previousHTML = draftJSEditorStateToHtml(editorState);
+                    const newHTML = draftJSEditorStateToHtml(newEditorState);
+                    if (newHTML !== previousHTML) {
+                        onChange(
+                            "text",
+                            draftJSEditorStateToHtml(newEditorState)
+                        );
+                        setEditorState(newEditorState);
+                    }
+                }}
+                // Array of custom or built in fonts can be set via props
+                // fonts={["Arial", "Impact", "Roman"]}
+            />
+        </div>
+    );
+}
+export default TextOptions;
diff --git a/web/client/themes/default/less/wizard.less b/web/client/themes/default/less/wizard.less
index f9e742b4ae..b0c092494a 100644
--- a/web/client/themes/default/less/wizard.less
+++ b/web/client/themes/default/less/wizard.less
@@ -30,7 +30,7 @@
 
 
 .ms-wizard {
-    position: absolute;
+    // position: absolute;
     width: 100%;
     .form-horizontal {
         .form-group {