diff --git a/projects/common/models/uI-element.ts b/projects/common/models/uI-element.ts
index 83873d87d7fb6592f22282f15e7f2c9cc2fec100..3b1e920165552e6ce96086a1f2ac9385c768247f 100644
--- a/projects/common/models/uI-element.ts
+++ b/projects/common/models/uI-element.ts
@@ -24,6 +24,9 @@ export abstract class UIElement {
   playerProps?: PlayerProperties;
 
   protected constructor(serializedElement: Partial<UIElement>) {
+    if (!serializedElement.type) {
+      throw Error('No element type given!');
+    }
     Object.assign(this, serializedElement);
   }
 
@@ -46,7 +49,7 @@ export abstract class UIElement {
   // This can be overwritten by elements if they need to handle some property specifics. Likert does.
   setProperty(property: string,
               value: InputElementValue | LikertColumn[] | LikertRow[] |
-              DragNDropValueObject[] | ClozePart[][]): void {
+              DragNDropValueObject[] | ClozeDocument): void {
     if (this.fontProps && property in this.fontProps) {
       this.fontProps[property] = value as string | number | boolean;
     } else if (this.surfaceProps && property in this.surfaceProps) {
@@ -62,7 +65,7 @@ export abstract class UIElement {
 }
 
 export abstract class InputElement extends UIElement {
-  label: string;
+  label?: string;
   value: InputElementValue;
   required: boolean;
   requiredWarnMessage: string;
@@ -81,6 +84,24 @@ export abstract class InputElement extends UIElement {
 
 export abstract class CompoundElement extends UIElement {}
 
+export interface ClozeDocument {
+  type: string;
+  content: ClozeDocumentParagraph[]
+}
+
+export interface ClozeDocumentParagraph {
+  type: string;
+  attrs: Record<string, string | number | boolean>;
+  content: ClozeDocumentPart[];
+}
+
+export interface ClozeDocumentPart {
+  type: string;
+  text?: string;
+  marks?: any;
+  attrs?: Record<string, string | number | boolean | InputElement>;
+}
+
 export interface ValueChangeElement {
   id: string;
   values: [InputElementValue, InputElementValue];
@@ -172,9 +193,3 @@ export interface LikertRow {
   text: string;
   columnCount: number;
 }
-
-export type ClozePart = {
-  type: string;
-  value: string | UIElement;
-  style?: string;
-};
diff --git a/projects/common/shared.module.ts b/projects/common/shared.module.ts
index d86aefabc67ed92b2277b7f5ba96bd8df80e4beb..b7234be929b968d3cb9d77b09cdb803cb64cbc62 100644
--- a/projects/common/shared.module.ts
+++ b/projects/common/shared.module.ts
@@ -50,6 +50,7 @@ import { DropListSimpleComponent } from './ui-elements/drop-list-simple/drop-lis
 import { FrameComponent } from './ui-elements/frame/frame.component';
 import { ToggleButtonComponent } from './ui-elements/toggle-button/toggle-button.component';
 import { MarkingBarComponent } from './components/marking-bar/marking-bar.component';
+import { MarkPipe } from './ui-elements/cloze/mark.pipe';
 
 @NgModule({
   imports: [
@@ -101,7 +102,8 @@ import { MarkingBarComponent } from './components/marking-bar/marking-bar.compon
     TextFieldSimpleComponent,
     FrameComponent,
     ToggleButtonComponent,
-    MarkingBarComponent
+    MarkingBarComponent,
+    MarkPipe
   ],
   exports: [
     CommonModule,
@@ -118,7 +120,11 @@ import { MarkingBarComponent } from './components/marking-bar/marking-bar.compon
     MatDialogModule,
     TranslateModule,
     SafeResourceHTMLPipe,
-    MarkingBarComponent
+    MarkingBarComponent,
+    ToggleButtonComponent,
+    TextFieldComponent,
+    DropListSimpleComponent,
+    TextFieldSimpleComponent
   ]
 })
 export class SharedModule {
diff --git a/projects/common/ui-elements/cloze/cloze-element.ts b/projects/common/ui-elements/cloze/cloze-element.ts
index 2f4901d8d8e0f37e96a1512c4cc9ea5c83d88bf1..426ccdf9c726fcdd175ca49af7555be622545fe8 100644
--- a/projects/common/ui-elements/cloze/cloze-element.ts
+++ b/projects/common/ui-elements/cloze/cloze-element.ts
@@ -1,25 +1,21 @@
+import { Editor } from '@tiptap/core';
+import StarterKit from '@tiptap/starter-kit';
+import ToggleButtonExtension from './tiptap-editor-extensions/toggle-button';
+import DropListExtension from './tiptap-editor-extensions/drop-list';
+import TextFieldExtension from './tiptap-editor-extensions/text-field';
 import {
-  ClozePart,
-  CompoundElement,
-  FontElement,
-  FontProperties, InputElement,
+  UIElement, InputElement, CompoundElement,
+  ClozeDocument,
   PositionedElement, PositionProperties,
-  UIElement
+  FontElement, FontProperties
 } from '../../models/uI-element';
 import { initFontElement, initPositionedElement } from '../../util/unit-interface-initializer';
 import { TextFieldSimpleElement } from '../textfield-simple/text-field-simple-element';
-import { TextFieldElement } from '../text-field/text-field-element';
-import { TextAreaElement } from '../text-area/text-area-element';
-import { CheckboxElement } from '../checkbox/checkbox-element';
-import { DropdownElement } from '../dropdown/dropdown-element';
 import { DropListSimpleElement } from '../drop-list-simple/drop-list-simple';
 import { ToggleButtonElement } from '../toggle-button/toggle-button';
 
-// TODO styles like em dont continue after inserted components
-
 export class ClozeElement extends CompoundElement implements PositionedElement, FontElement {
-  text: string = 'Lorem ipsum dolor \\r sdfsdf \\i sdfsdf';
-  parts: ClozePart[][] = [];
+  document: ClozeDocument = { type: 'doc', content: [] };
 
   positionProps: PositionProperties;
   fontProps: FontProperties;
@@ -30,40 +26,91 @@ export class ClozeElement extends CompoundElement implements PositionedElement,
     this.positionProps = initPositionedElement(serializedElement);
     this.fontProps = initFontElement(serializedElement);
 
-    if (serializedElement?.parts) {
-      serializedElement?.parts.forEach((subParts: ClozePart[]) => {
-        subParts.forEach((part: ClozePart) => {
-          if (!['p', 'h1', 'h2', 'h3', 'h4'].includes(part.type)) {
-            part.value = ClozeElement.createElement(part.value as UIElement);
+    if (serializedElement.document) {
+      serializedElement.document.content.forEach((paragraph: any) => {
+        paragraph.content?.forEach((node: any) => {
+          if (['ToggleButton', 'DropList', 'TextField'].includes(node.type)) {
+            node.attrs.model = ClozeElement.createElement(node.attrs.model);
           }
         });
       });
     }
 
+    // text property indicates old unit definition
+    if (serializedElement.text) {
+      this.handleBackwardsCompatibility(serializedElement);
+    }
+
     this.width = serializedElement.width || 450;
     this.height = serializedElement.height || 200;
   }
 
-  static createElement(elementModel: Partial<UIElement>): InputElement {
+  private handleBackwardsCompatibility(serializedElement: Partial<UIElement>): void {
+    const childModels = ClozeElement.parseElementList(serializedElement.parts);
+
+    const textFieldElementList = Object.values(childModels).filter((el: any) => el.type === 'text-field');
+    const dropListElementList = Object.values(childModels).filter((el: any) => el.type === 'drop-list');
+    const radioElementList = Object.values(childModels).filter((el: any) => el.type === 'toggle-button');
+
+    const replacedText = (serializedElement.text as string).replace(/\\i|\\z|\\r/g, match => {
+      switch (match) {
+        case '\\i':
+          return `<app-nodeview-text-field id="${textFieldElementList.shift()?.id}"></app-nodeview-text-field>`;
+          break;
+        case '\\z':
+          return `<app-nodeview-drop-list id="${dropListElementList.shift()?.id}"></app-nodeview-drop-list>`;
+          break;
+        case '\\r':
+          return `<app-nodeview-toggle-button id="${radioElementList.shift()?.id}"></app-nodeview-toggle-button>`;
+          break;
+        default:
+          throw Error('error in match');
+      }
+      return match;
+    });
+
+    if (textFieldElementList.length === 0 ||
+        dropListElementList.length === 0 ||
+        radioElementList.length === 0) {
+      throw Error('Error while reading cloze element!');
+    }
+
+    const editor = new Editor({
+      extensions: [
+        StarterKit,
+        ToggleButtonExtension,
+        DropListExtension,
+        TextFieldExtension
+      ],
+      content: replacedText
+    });
+    this.document = editor.getJSON() as ClozeDocument;
+  }
+
+  private static parseElementList(
+    serializedParts: { type: string; value: string | UIElement; style?: string; }[][]
+  ): InputElement[] {
+    const knownElementTypes = ['text-field', 'drop-list', 'toggle-button'];
+    const newElementList: InputElement[] = [];
+
+    serializedParts.forEach((part: any) => {
+      for (const subPart of part) {
+        if (knownElementTypes.includes(subPart.type)) {
+          newElementList.push(subPart.value);
+        }
+      }
+    });
+    return newElementList;
+  }
+
+  private static createElement(elementModel: Partial<UIElement>): InputElement {
     let newElement: InputElement;
     switch (elementModel.type) {
       case 'text-field':
         newElement = new TextFieldSimpleElement(elementModel);
-        (newElement as TextFieldElement).label = '';
-        break;
-      case 'text-area':
-        newElement = new TextAreaElement(elementModel);
-        break;
-      case 'checkbox':
-        newElement = new CheckboxElement(elementModel);
-        break;
-      case 'dropdown':
-        newElement = new DropdownElement(elementModel);
         break;
       case 'drop-list':
         newElement = new DropListSimpleElement(elementModel);
-        newElement.height = 25; // TODO weg?
-        newElement.width = 100;
         break;
       case 'toggle-button':
         newElement = new ToggleButtonElement(elementModel);
diff --git a/projects/common/ui-elements/cloze/cloze.component.ts b/projects/common/ui-elements/cloze/cloze.component.ts
index 1348395a1db27ca5629c01a8d80f059150fe7ab2..436d1c99f3b7db287de30d8582d67e8247e98d0a 100644
--- a/projects/common/ui-elements/cloze/cloze.component.ts
+++ b/projects/common/ui-elements/cloze/cloze.component.ts
@@ -1,93 +1,83 @@
 import {
-  Component, EventEmitter, Output, QueryList, ViewChildren
+  Component, EventEmitter, Input, Output, QueryList, ViewChildren
 } from '@angular/core';
 import { ClozeElement } from './cloze-element';
 import { CompoundElementComponent } from '../../directives/compound-element.directive';
-import { InputElement, ClozePart } from '../../models/uI-element';
+import { ClozeDocumentParagraph, ClozeDocumentPart, InputElement } from '../../models/uI-element';
 import { FormElementComponent } from '../../directives/form-element-component.directive';
 
 @Component({
   selector: 'app-cloze',
   template: `
+    <ng-container *ngIf="elementModel.document.content.length == 0">
+      Kein Dokument vorhanden
+    </ng-container>
     <div [class.center-content]="elementModel.positionProps.dynamicPositioning &&
                                  elementModel.positionProps.fixedSize"
          [style.width]="elementModel.positionProps.fixedSize ? elementModel.width + 'px' : '100%'"
          [style.height]="elementModel.positionProps.fixedSize ? elementModel.height + 'px' : 'auto'">
-      <p *ngFor="let paragraph of elementModel.parts; let i = index"
-         [style.line-height.%]="elementModel.fontProps.lineHeight"
-         [style.color]="elementModel.fontProps.fontColor"
-         [style.font-family]="elementModel.fontProps.font"
-         [style.font-size.px]="elementModel.fontProps.fontSize"
-         [style.font-weight]="elementModel.fontProps.bold ? 'bold' : ''"
-         [style.font-style]="elementModel.fontProps.italic ? 'italic' : ''"
-         [style.text-decoration]="elementModel.fontProps.underline ? 'underline' : ''">
-        <ng-container *ngFor="let part of paragraph; let j = index">
-
-          <span *ngIf="part.type === 'p'"
-               [innerHTML]="part.value"
-               [style]="part.style">
-          </span>
-
-          <h1 *ngIf="part.type === 'h1'"
-              [innerHTML]="part.value"
-              [style.display]="'inline'"
-              [style]="part.style">
-          </h1>
-          <h2 *ngIf="part.type === 'h2'"
-              [innerHTML]="part.value"
-              [style.display]="'inline'"
-              [style]="part.style">
-          </h2>
-          <h3 *ngIf="part.type === 'h3'"
-              [innerHTML]="part.value"
-              [style.display]="'inline'"
-              [style]="part.style">
-          </h3>
-          <h4 *ngIf="part.type === 'h4'"
-              [innerHTML]="part.value"
-              [style.display]="'inline'"
-              [style]="part.style">
-          </h4>
-
-          <span (click)="allowClickThrough || selectElement($any(part.value), $event)">
-            <app-dropdown *ngIf="part.type === 'dropdown'" #drowdownComponent
-                          [parentForm]="parentForm"
-                          [style.display]="'inline-block'"
-                          [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
-                          [elementModel]="$any(part.value)"
-                          (elementValueChanged)="elementValueChanged.emit($event)">
-            </app-dropdown>
-            <app-text-field-simple *ngIf="part.type === 'text-field'" #textfieldComponent
-                            [parentForm]="parentForm"
-                            [style.display]="'inline-block'"
-                            [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
-                            [elementModel]="$any(part.value)"
-                            (elementValueChanged)="elementValueChanged.emit($event)">
-            </app-text-field-simple>
-
-            <app-toggle-button *ngIf="part.type === 'toggle-button'" #radioComponent
-                            [parentForm]="parentForm"
-                            [style.display]="'inline-block'"
-                            [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
-                            [elementModel]="$any(part.value)"
-                            (elementValueChanged)="elementValueChanged.emit($event)">
-            </app-toggle-button>
-
-            <div *ngIf="part.type === 'drop-list'"
-                 [style.display]="'inline-block'"
-                 [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
-                 [style.vertical-align]="'middle'"
-                 [style.width.px]="$any(part.value).width"
-                 [style.height.px]="$any(part.value).height">
-              <app-drop-list-simple #droplistComponent
-                             [parentForm]="parentForm"
-                             (elementValueChanged)="elementValueChanged.emit($event)"
-                             [elementModel]="$any(part.value)">
-              </app-drop-list-simple>
-            </div>
-          </span>
-        </ng-container>
-      </p>
+      <ng-container *ngFor="let part of elementModel.document.content">
+        <p *ngIf="part.type === 'paragraph'"
+           [style.line-height.%]="elementModel.fontProps.lineHeight"
+           [style.color]="elementModel.fontProps.fontColor"
+           [style.font-family]="elementModel.fontProps.font"
+           [style.font-size.px]="elementModel.fontProps.fontSize"
+           [style.font-weight]="elementModel.fontProps.bold ? 'bold' : ''"
+           [style.font-style]="elementModel.fontProps.italic ? 'italic' : ''"
+           [style.text-decoration]="elementModel.fontProps.underline ? 'underline' : ''">
+          <ng-container *ngFor="let subPart of part.content">
+            <ng-container *ngIf="subPart.type === 'text'">
+              <span [style.font-weight]="$any((subPart.marks | mark)?.includes('bold')) ? 'bold' : ''"
+                    [style.font-style]="$any((subPart.marks | mark)?.includes('italic')) ? 'italic' : ''"
+                    [style.text-decoration]="$any((subPart.marks | mark)?.includes('underline')) ? 'underline' : ''">
+                {{subPart.text}}
+              </span>
+            </ng-container>
+            <span *ngIf="['ToggleButton', 'DropList', 'TextField'].includes(subPart.type)"
+                  (click)="selectElement($any(subPart.attrs).model, $event)">
+                <app-toggle-button *ngIf="subPart.type === 'ToggleButton'" #radioComponent
+                                   [parentForm]="parentForm"
+                                   [style.display]="'inline-block'"
+                                   [style.vertical-align]="'middle'"
+                                   [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
+                                   [elementModel]="$any(subPart.attrs).model"
+                                   (elementValueChanged)="elementValueChanged.emit($event)">
+                </app-toggle-button>
+                <app-text-field-simple *ngIf="subPart.type === 'TextField'" #textfieldComponent
+                                       [parentForm]="parentForm"
+                                       [style.display]="'inline-block'"
+                                       [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
+                                       [elementModel]="$any(subPart.attrs).model"
+                                       (elementValueChanged)="elementValueChanged.emit($event)">
+                </app-text-field-simple>
+                <app-drop-list-simple *ngIf="subPart.type === 'DropList'" #droplistComponent
+                                      [parentForm]="parentForm"
+                                      [style.display]="'inline-block'"
+                                      [style.vertical-align]="'middle'"
+                                      [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
+                                      [elementModel]="$any(subPart.attrs).model"
+                                      (elementValueChanged)="elementValueChanged.emit($event)">
+                </app-drop-list-simple>
+            </span>
+          </ng-container>
+        </p>
+        <h1 *ngIf="part.type === 'heading' && part.attrs.level === 1"
+            [style.display]="'inline'">
+          {{part.content[0].text}}
+        </h1>
+        <h2 *ngIf="part.type === 'heading' && part.attrs.level === 2"
+            [style.display]="'inline'">
+          {{part.content[0].text}}
+        </h2>
+        <h3 *ngIf="part.type === 'heading' && part.attrs.level === 3"
+            [style.display]="'inline'">
+          {{part.content[0].text}}
+        </h3>
+        <h4 *ngIf="part.type === 'heading' && part.attrs.level === 4"
+            [style.display]="'inline'">
+          {{part.content[0].text}}
+        </h4>
+      </ng-container>
     </div>
   `,
   styles: [
@@ -96,25 +86,24 @@ import { FormElementComponent } from '../../directives/form-element-component.di
     ':host ::ng-deep app-text-field .mat-form-field {height: 100%}',
     ':host ::ng-deep app-text-field .mat-form-field-flex {height: 100%}',
     'p {margin: 0}',
+    ':host ::ng-deep p strong {letter-spacing: 0.04em; font-weight: 600;}', // bold less bold
+    ':host ::ng-deep p:empty::after {content: "\\00A0"}', // render empty p
     'p span {font-size: inherit}'
   ]
 })
 export class ClozeComponent extends CompoundElementComponent {
-  elementModel!: ClozeElement;
+  @Input() elementModel!: ClozeElement;
   @Output() elementSelected = new EventEmitter<{ element: ClozeElement, event: MouseEvent }>();
   @ViewChildren('drowdownComponent, textfieldComponent, droplistComponent, radioComponent')
   compoundChildren!: QueryList<FormElementComponent>;
 
   getFormElementModelChildren(): InputElement[] {
-    const uiElements: InputElement[] = [];
-    this.elementModel.parts.forEach((subParts: ClozePart[]) => {
-      subParts.forEach((part: ClozePart) => {
-        if (part.value instanceof InputElement) {
-          uiElements.push(part.value);
-        }
-      });
-    });
-    return uiElements;
+    return this.elementModel.document.content
+      .filter((paragraph: ClozeDocumentParagraph) => paragraph.content) // filter empty paragraphs
+      .map((paragraph: ClozeDocumentParagraph) => paragraph.content // get custom paragraph parts
+        .filter((word: ClozeDocumentPart) => ['TextField', 'DropList', 'ToggleButton'].includes(word.type)))
+      .reduce((accumulator: any[], currentValue: any) => accumulator // put all collected paragraph parts into one list
+        .concat(currentValue.map((node: ClozeDocumentPart) => node.attrs?.model)), []); // model is in node.attrs.model
   }
 
   selectElement(element: ClozeElement, event: MouseEvent): void {
diff --git a/projects/common/ui-elements/cloze/mark.pipe.ts b/projects/common/ui-elements/cloze/mark.pipe.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d9b24d9e0a645f01f38bb62826c37b08f321b05b
--- /dev/null
+++ b/projects/common/ui-elements/cloze/mark.pipe.ts
@@ -0,0 +1,15 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'mark'
+})
+/* This extracts marks from an item and puts them is a list to be searchable.
+  Only used in cloze component */
+export class MarkPipe implements PipeTransform {
+  transform(items: any[]): any[] {
+    if (!items) {
+      return items;
+    }
+    return items.map(item => item.type);
+  }
+}
diff --git a/projects/common/ui-elements/cloze/tiptap-editor-extensions/drop-list.ts b/projects/common/ui-elements/cloze/tiptap-editor-extensions/drop-list.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9aea0b7cd50a86e96df6919f7d195af581cf6d13
--- /dev/null
+++ b/projects/common/ui-elements/cloze/tiptap-editor-extensions/drop-list.ts
@@ -0,0 +1,25 @@
+import { Node, mergeAttributes } from '@tiptap/core';
+
+const DropListExtension =
+  Node.create({
+    group: 'inline',
+    inline: true,
+    name: 'DropList',
+
+    addAttributes() {
+      return {
+        id: {
+          default: 'will be generated'
+        }
+      };
+    },
+
+    parseHTML() {
+      return [{ tag: 'app-nodeview-drop-list' }];
+    },
+    renderHTML({ HTMLAttributes }) {
+      return ['app-nodeview-drop-list', mergeAttributes(HTMLAttributes)];
+    }
+  });
+
+export default DropListExtension;
diff --git a/projects/common/ui-elements/cloze/tiptap-editor-extensions/text-field.ts b/projects/common/ui-elements/cloze/tiptap-editor-extensions/text-field.ts
new file mode 100644
index 0000000000000000000000000000000000000000..251cc0385f442deb58dac267993001cc80929933
--- /dev/null
+++ b/projects/common/ui-elements/cloze/tiptap-editor-extensions/text-field.ts
@@ -0,0 +1,25 @@
+import { Node, mergeAttributes } from '@tiptap/core';
+
+const TextFieldExtension =
+  Node.create({
+    group: 'inline',
+    inline: true,
+    name: 'TextField',
+
+    addAttributes() {
+      return {
+        id: {
+          default: 'will be generated'
+        }
+      };
+    },
+
+    parseHTML() {
+      return [{ tag: 'app-nodeview-text-field' }];
+    },
+    renderHTML({ HTMLAttributes }) {
+      return ['app-nodeview-text-field', mergeAttributes(HTMLAttributes)];
+    }
+  });
+
+export default TextFieldExtension;
diff --git a/projects/common/ui-elements/cloze/tiptap-editor-extensions/toggle-button.ts b/projects/common/ui-elements/cloze/tiptap-editor-extensions/toggle-button.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1cf4d2e8f72ea9a0a374a549f01624e114898040
--- /dev/null
+++ b/projects/common/ui-elements/cloze/tiptap-editor-extensions/toggle-button.ts
@@ -0,0 +1,25 @@
+import { Node, mergeAttributes } from '@tiptap/core';
+
+const ToggleButtonExtension =
+  Node.create({
+    group: 'inline',
+    inline: true,
+    name: 'ToggleButton',
+
+    addAttributes() {
+      return {
+        id: {
+          default: 'will be generated'
+        }
+      };
+    },
+
+    parseHTML() {
+      return [{ tag: 'app-nodeview-toggle-button' }];
+    },
+    renderHTML({ HTMLAttributes }) {
+      return ['app-nodeview-toggle-button', mergeAttributes(HTMLAttributes)];
+    }
+  });
+
+export default ToggleButtonExtension;
diff --git a/projects/common/ui-elements/drop-list-simple/drop-list-simple.component.ts b/projects/common/ui-elements/drop-list-simple/drop-list-simple.component.ts
index c73ae3e6a6a9ffd2cc82fa6eeeb08173fe21c74e..80baa100e1748a67ae826a50482f201598887e98 100644
--- a/projects/common/ui-elements/drop-list-simple/drop-list-simple.component.ts
+++ b/projects/common/ui-elements/drop-list-simple/drop-list-simple.component.ts
@@ -14,6 +14,8 @@ import { DragNDropValueObject } from '../../models/uI-element';
       <!-- Border width is a workaround to enable/disable the Material cdk-drop-list-receiving-->
       <!-- class style.-->
       <div class="list"
+           [style.height.px]="elementModel.height"
+           [style.width.px]="elementModel.width"
            [class.dropList-highlight]="elementModel.highlightReceivingDropList"
            [style.border-color]="elementModel.highlightReceivingDropListColor"
            [style.border-width.px]="elementModel.highlightReceivingDropList ? 2 : 0"
diff --git a/projects/common/ui-elements/drop-list-simple/drop-list-simple.ts b/projects/common/ui-elements/drop-list-simple/drop-list-simple.ts
index 41e4cd41139d6f87729a5a449d4eaf72d57b48c5..c04b847eae99e3678090664c45b368c67aeac788 100644
--- a/projects/common/ui-elements/drop-list-simple/drop-list-simple.ts
+++ b/projects/common/ui-elements/drop-list-simple/drop-list-simple.ts
@@ -2,12 +2,11 @@ import {
   FontElement,
   FontProperties,
   InputElement,
-  PositionedElement, PositionProperties,
   SurfaceElement,
   SurfaceProperties,
   UIElement
 } from '../../models/uI-element';
-import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer';
+import { initFontElement, initSurfaceElement } from '../../util/unit-interface-initializer';
 
 export class DropListSimpleElement extends InputElement implements FontElement, SurfaceElement {
   connectedTo: string[] = [];
@@ -24,6 +23,8 @@ export class DropListSimpleElement extends InputElement implements FontElement,
     this.fontProps = initFontElement(serializedElement);
     this.surfaceProps = initSurfaceElement(serializedElement);
 
+    delete this.label;
+
     this.value = serializedElement.value as string[] || [];
     this.height = serializedElement.height || 100;
     this.surfaceProps.backgroundColor =
diff --git a/projects/common/ui-elements/textfield-simple/text-field-simple-element.ts b/projects/common/ui-elements/textfield-simple/text-field-simple-element.ts
index b06fb78999eae6ef87b0bc7a76a7ce684e2da84b..4f94232578596fb224273206377c557a68d62ac5 100644
--- a/projects/common/ui-elements/textfield-simple/text-field-simple-element.ts
+++ b/projects/common/ui-elements/textfield-simple/text-field-simple-element.ts
@@ -18,6 +18,8 @@ export class TextFieldSimpleElement extends InputElement implements FontElement,
     this.fontProps = initFontElement(serializedElement);
     this.surfaceProps = initSurfaceElement(serializedElement);
 
+    delete this.label;
+
     this.height = serializedElement.height || 25;
   }
 }
diff --git a/projects/common/ui-elements/toggle-button/toggle-button.component.ts b/projects/common/ui-elements/toggle-button/toggle-button.component.ts
index 2ca71171d6eda9f0fa4e287e5a9062c4d2181bb1..cdb8f6f59ccf1ce75174756810bd67909e23ba79 100644
--- a/projects/common/ui-elements/toggle-button/toggle-button.component.ts
+++ b/projects/common/ui-elements/toggle-button/toggle-button.component.ts
@@ -8,7 +8,9 @@ import { FormElementComponent } from '../../directives/form-element-component.di
     <div class="mat-form-field">
       <mat-button-toggle-group [formControl]="elementFormControl"
                                [value]="elementModel.value"
-                               [style.height.px]="elementModel.height">
+                               [style.height.px]="elementModel.height"
+                               [style.width]="elementModel.dynamicWidth ? 'unset' : elementModel.width+'px'"
+                               [vertical]="elementModel.verticalOrientation">
         <mat-button-toggle *ngFor="let option of elementModel.options; let i = index"
                            [value]="i"
                            [ngClass]="{ 'strike' : elementModel.strikeOtherOptions &&
@@ -25,6 +27,7 @@ import { FormElementComponent } from '../../directives/form-element-component.di
                                                    elementModel.selectionColor :
                                                    elementModel.surfaceProps.backgroundColor"
                            [style.line-height.%]="elementModel.fontProps.lineHeight">
+                           <!--Background color does not show in editor-->
           {{option}}
         </mat-button-toggle>
       </mat-button-toggle-group>
@@ -32,8 +35,9 @@ import { FormElementComponent } from '../../directives/form-element-component.di
   `,
   styles: [
     'mat-button-toggle-group {min-width: 70px; min-height: 20px}',
+    ':host ::ng-deep mat-button-toggle {width: 100%; height: 100%}',
     ':host ::ng-deep .mat-button-toggle-button {height: 100%}',
-    ':host ::ng-deep .mat-button-toggle-label-content {height: 100%; line-height: unset}',
+    ':host ::ng-deep .mat-button-toggle-label-content {line-height: unset}',
     ':host ::ng-deep .strike .mat-button-toggle-label-content {text-decoration: line-through}'
   ]
 })
diff --git a/projects/common/ui-elements/toggle-button/toggle-button.ts b/projects/common/ui-elements/toggle-button/toggle-button.ts
index e950a0cdd3e216bfe60dc300e675f08cebe0db09..b90c98a29744c57bd5fed4a3a83c06bf50bf8f04 100644
--- a/projects/common/ui-elements/toggle-button/toggle-button.ts
+++ b/projects/common/ui-elements/toggle-button/toggle-button.ts
@@ -8,9 +8,11 @@ import {
 import { initFontElement, initSurfaceElement } from '../../util/unit-interface-initializer';
 
 export class ToggleButtonElement extends InputElement implements FontElement, SurfaceElement {
-  options: string[] = ['abc', 'def'];
+  options: string[] = ['A', 'B'];
   strikeOtherOptions: boolean = false;
   selectionColor: string = 'lightgreen';
+  verticalOrientation = false;
+  dynamicWidth: boolean = true;
 
   fontProps: FontProperties;
   surfaceProps: SurfaceProperties;
@@ -21,6 +23,8 @@ export class ToggleButtonElement extends InputElement implements FontElement, Su
     this.fontProps = initFontElement(serializedElement);
     this.surfaceProps = initSurfaceElement(serializedElement);
 
+    delete this.label;
+
     this.height = serializedElement.height as number || 25;
     this.surfaceProps.backgroundColor =
       serializedElement.surfaceProps?.backgroundColor as string ||
diff --git a/projects/editor/src/app/app.module.ts b/projects/editor/src/app/app.module.ts
index 60aea9f31506606ce20e4748ed4de5c7ad66e1f8..9e914deb1ab467bb5bb0b47ec393bf988aa08dfb 100644
--- a/projects/editor/src/app/app.module.ts
+++ b/projects/editor/src/app/app.module.ts
@@ -53,6 +53,10 @@ import { ElementModelPropertiesComponent } from
   './components/unit-view/page-view/properties-panel/element-model-properties.component';
 import { DropListOptionEditDialogComponent } from './components/dialogs/drop-list-option-edit-dialog.component';
 
+import { ToggleButtonNodeviewComponent } from './text-editor/angular-node-views/toggle-button-nodeview.component';
+import { TextFieldNodeviewComponent } from './text-editor/angular-node-views/text-field-nodeview.component';
+import { DropListNodeviewComponent } from './text-editor/angular-node-views/drop-list-nodeview.component';
+
 @NgModule({
   declarations: [
     AppComponent,
@@ -68,6 +72,9 @@ import { DropListOptionEditDialogComponent } from './components/dialogs/drop-lis
     SectionStaticComponent,
     SectionDynamicComponent,
     RichTextEditorComponent,
+    ToggleButtonNodeviewComponent,
+    TextFieldNodeviewComponent,
+    DropListNodeviewComponent,
     ElementStylePropertiesComponent,
     ElementSizingPropertiesComponent,
     ConfirmationDialogComponent,
diff --git a/projects/editor/src/app/components/dialogs/rich-text-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/rich-text-edit-dialog.component.ts
index 65f19fb8ffa7b7997fa6c2dfabed2e50ba686ce1..366cd8390e3ac81237936e65ffd8a62bae580ce8 100644
--- a/projects/editor/src/app/components/dialogs/rich-text-edit-dialog.component.ts
+++ b/projects/editor/src/app/components/dialogs/rich-text-edit-dialog.component.ts
@@ -1,24 +1,25 @@
 import { Component, Inject } from '@angular/core';
 import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { ClozeDocument } from '../../../../../common/models/uI-element';
 
 @Component({
   selector: 'app-rich-text-edit-dialog',
   template: `
     <mat-dialog-content>
-      <app-rich-text-editor [(text)]="data.text"
-                            [showCloseElements]="data.showCloseElements"
+      <app-rich-text-editor [(content)]="data.content"
+                            [clozeMode]="data.clozeMode"
                             [defaultFontSize]="data.defaultFontSize">
       </app-rich-text-editor>
     </mat-dialog-content>
     <mat-dialog-actions>
-      <button mat-button [mat-dialog-close]="data.text">{{'save' | translate }}</button>
+      <button mat-button [mat-dialog-close]="data.content">{{'save' | translate }}</button>
       <button mat-button mat-dialog-close>{{'cancel' | translate }}</button>
     </mat-dialog-actions>
-    `
+  `
 })
 export class RichTextEditDialogComponent {
   constructor(@Inject(MAT_DIALOG_DATA) public data: {
-    text: string,
+    content: string | Record<string, any>,
     defaultFontSize: number,
-    showCloseElements?: boolean }) { }
+    clozeMode: boolean }) { }
 }
diff --git a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties.component.html b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties.component.html
index 9082ba1648fc57be9aad39ee699e578a6cfb0cbc..8b89dd85724b6a9a0cb1da42857e4967c4935706 100644
--- a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties.component.html
+++ b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties.component.html
@@ -19,6 +19,12 @@
     </div>
   </ng-container>
 
+  <ng-container *ngIf="combinedProperties.document">
+    <button (click)="unitService.showDefaultEditDialog(selectedElements[0])">
+      <mat-icon>build_circle</mat-icon>
+    </button>
+  </ng-container>
+
   <ng-container *ngIf="combinedProperties.playerProps">
     <button (click)="unitService.showDefaultEditDialog(selectedElements[0])">
       <mat-icon>build_circle</mat-icon>
@@ -517,6 +523,12 @@
     </mat-select>
   </mat-form-field>
 
+  <mat-checkbox *ngIf="combinedProperties.verticalOrientation !== undefined"
+                [checked]="$any(combinedProperties.verticalOrientation)"
+                (change)="updateModel.emit({ property: 'verticalOrientation', value: $event.checked })">
+    {{'propertiesPanel.verticalOrientation' | translate }}
+  </mat-checkbox>
+
   <mat-checkbox *ngIf="combinedProperties.onlyOneItem !== undefined"
                 [checked]="$any(combinedProperties.onlyOneItem)"
                 (change)="updateModel.emit({ property: 'onlyOneItem', value: $event.checked })">
diff --git a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-sizing-properties.component.ts b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-sizing-properties.component.ts
index c4dd9d9d324b865772b7adc085a5d7a3748e2425..4b78ca844fbd214cf3bcd5b05cd3995383c03c1b 100644
--- a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-sizing-properties.component.ts
+++ b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-sizing-properties.component.ts
@@ -9,8 +9,15 @@ import { PositionedElement, UIElement } from '../../../../../../../common/models
   selector: 'app-element-sizing-properties',
   template: `
     <div fxLayout="column">
+      <mat-checkbox *ngIf="combinedProperties.dynamicWidth !== undefined"
+                    [checked]="$any(combinedProperties.dynamicWidth)"
+                    (change)="updateModel.emit({ property: 'dynamicWidth', value: $event.checked })">
+        {{'propertiesPanel.dynamicWidth' | translate }}
+      </mat-checkbox>
+
       <ng-container *ngIf="!combinedProperties.dynamicPositioning; else elseBlock">
-        <mat-form-field appearance="fill">
+        <mat-form-field *ngIf="combinedProperties.dynamicWidth === undefined ||
+                               !combinedProperties.dynamicWidth" appearance="fill">
           <mat-label>{{'propertiesPanel.width' | translate }}</mat-label>
           <input matInput type="number" #width="ngModel" min="0"
                  [ngModel]="combinedProperties.width"
diff --git a/projects/editor/src/app/services/dialog.service.ts b/projects/editor/src/app/services/dialog.service.ts
index eb0e2cdfd9da8a9f580cb1fcdaba98760c6e3e52..6ad291ec27030e8d09d86213927ccc802855664b 100644
--- a/projects/editor/src/app/services/dialog.service.ts
+++ b/projects/editor/src/app/services/dialog.service.ts
@@ -10,6 +10,7 @@ import { PlayerEditDialogComponent } from '../components/dialogs/player-edit-dia
 import { LikertColumnEditDialogComponent } from '../components/dialogs/likert-column-edit-dialog.component';
 import { LikertRowEditDialogComponent } from '../components/dialogs/likert-row-edit-dialog.component';
 import {
+  ClozeDocument,
   DragNDropValueObject, LikertColumn, PlayerProperties
 } from '../../../../common/models/uI-element';
 import { DropListOptionEditDialogComponent } from '../components/dialogs/drop-list-option-edit-dialog.component';
@@ -50,15 +51,15 @@ export class DialogService {
 
   showRichTextEditDialog(text: string, defaultFontSize: number): Observable<string> {
     const dialogRef = this.dialog.open(RichTextEditDialogComponent, {
-      data: { text, defaultFontSize },
+      data: { content: text, defaultFontSize },
       autoFocus: false
     });
     return dialogRef.afterClosed();
   }
 
-  showClozeTextEditDialog(text: string): Observable<string> {
+  showClozeTextEditDialog(document: ClozeDocument, defaultFontSize: number): Observable<string> {
     const dialogRef = this.dialog.open(RichTextEditDialogComponent, {
-      data: { text, showCloseElements: true },
+      data: { content: document, defaultFontSize, clozeMode: true },
       autoFocus: false
     });
     return dialogRef.afterClosed();
diff --git a/projects/editor/src/app/services/unit.service.ts b/projects/editor/src/app/services/unit.service.ts
index ce26bfb892cde3543556efbd960ed72093e2edda..7648242f51b1d0c5409101d0eefa282601197332 100644
--- a/projects/editor/src/app/services/unit.service.ts
+++ b/projects/editor/src/app/services/unit.service.ts
@@ -15,7 +15,7 @@ import {
   InputElement, InputElementValue,
   LikertColumn,
   LikertRow, PlayerElement,
-  PlayerProperties, PositionedElement,
+  PlayerProperties, PositionedElement, ClozeDocument,
   UIElement,
   UIElementType
 } from '../../../../common/models/uI-element';
@@ -26,6 +26,7 @@ import { SelectionService } from './selection.service';
 import { ElementFactory } from '../../../../common/util/element.factory';
 import { ClozeParser } from '../util/cloze-parser';
 import { Copy } from '../../../../common/util/copy';
+import { ClozeElement } from '../../../../common/ui-elements/cloze/cloze-element';
 
 @Injectable({
   providedIn: 'root'
@@ -246,7 +247,7 @@ export class UnitService {
   }
 
   updateElementProperty(elements: UIElement[], property: string,
-                        value: InputElementValue | LikertColumn[] | LikertRow[] |
+                        value: InputElementValue | LikertColumn[] | LikertRow[] | ClozeDocument |
                         DragNDropValueObject[] | null): boolean {
     // console.log('updateElementProperty', elements, property, value);
     for (const element of elements) {
@@ -258,9 +259,11 @@ export class UnitService {
         this.idService.removeId(element.id);
         this.idService.addID(value as string);
         element.setProperty('id', value);
-      } else if (property === 'text' && element.type === 'cloze') {
-        element.setProperty('parts', ClozeParser.createClozeParts(value as string, this.idService));
-        element.setProperty('text', value);
+      } else if (property === 'document') {
+        element.setProperty('document', ClozeParser.setMissingIDs(
+          value as ClozeDocument,
+          this.idService
+        ));
       } else {
         element.setProperty(property, Copy.getCopy(value));
       }
@@ -408,7 +411,7 @@ export class UnitService {
       case 'dropdown':
       case 'checkbox':
       case 'radio':
-        this.dialogService.showTextEditDialog((element as InputElement).label).subscribe((result: string) => {
+        this.dialogService.showTextEditDialog(element.label).subscribe((result: string) => {
           if (result) {
             this.updateElementProperty([element], 'label', result);
           }
@@ -429,12 +432,15 @@ export class UnitService {
         });
         break;
       case 'cloze':
-        this.dialogService.showClozeTextEditDialog((element as TextElement).text).subscribe((result: string) => {
+        this.dialogService.showClozeTextEditDialog(
+          element.document,
+          (element as ClozeElement).fontProps.fontSize as number
+        ).subscribe((result: string) => {
           if (result) {
             // TODO add proper sanitization
             this.updateElementProperty(
               [element],
-              'text',
+              'document',
               (this.sanitizer.bypassSecurityTrustHtml(result) as any).changingThisBreaksApplicationSecurity as string
             );
           }
diff --git a/projects/editor/src/app/text-editor/angular-node-views/drop-list-component-extension.ts b/projects/editor/src/app/text-editor/angular-node-views/drop-list-component-extension.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4892497b8b9f71d6ad2e88c3d997c855d4014c61
--- /dev/null
+++ b/projects/editor/src/app/text-editor/angular-node-views/drop-list-component-extension.ts
@@ -0,0 +1,33 @@
+import { Injector } from '@angular/core';
+import { Node, mergeAttributes } from '@tiptap/core';
+import { AngularNodeViewRenderer } from 'ngx-tiptap';
+import { DropListNodeviewComponent } from './drop-list-nodeview.component';
+import { DropListSimpleElement } from '../../../../../common/ui-elements/drop-list-simple/drop-list-simple';
+
+const DropListComponentExtension = (injector: Injector): Node => {
+  return Node.create({
+    group: 'inline',
+    inline: true,
+    name: 'DropList',
+
+    addAttributes() {
+      return {
+        model: {
+          default: new DropListSimpleElement({ type: 'drop-list', height: 25, width: 100 })
+        }
+      };
+    },
+
+    parseHTML() {
+      return [{ tag: 'app-nodeview-drop-list' }];
+    },
+    renderHTML({ HTMLAttributes }) {
+      return ['app-nodeview-drop-list', mergeAttributes(HTMLAttributes)];
+    },
+    addNodeView() {
+      return AngularNodeViewRenderer(DropListNodeviewComponent, { injector });
+    }
+  });
+};
+
+export default DropListComponentExtension;
diff --git a/projects/editor/src/app/text-editor/angular-node-views/drop-list-nodeview.component.ts b/projects/editor/src/app/text-editor/angular-node-views/drop-list-nodeview.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f510c1f665eaf3b90f97989dc5a6baf2890f4f7a
--- /dev/null
+++ b/projects/editor/src/app/text-editor/angular-node-views/drop-list-nodeview.component.ts
@@ -0,0 +1,24 @@
+import { Component } from '@angular/core';
+import { AngularNodeViewComponent } from 'ngx-tiptap';
+import { DropListSimpleElement } from '../../../../../common/ui-elements/drop-list-simple/drop-list-simple';
+
+@Component({
+  selector: 'app-nodeview-drop-list',
+  template: `
+    <div [style.display]="'inline-block'"
+         [style.vertical-align]="'middle'"
+         [style.width.px]="model.width"
+         [style.height.px]="model.height">
+      <app-drop-list-simple [elementModel]="node.attrs.model"
+                            [matTooltip]="'ID: ' + node.attrs.model.id">
+      </app-drop-list-simple>
+    </div>
+  `
+})
+export class DropListNodeviewComponent extends AngularNodeViewComponent {
+  model: DropListSimpleElement = new DropListSimpleElement({
+    type: 'drop-list',
+    height: 25,
+    width: 100
+  });
+}
diff --git a/projects/editor/src/app/text-editor/angular-node-views/text-field-component-extension.ts b/projects/editor/src/app/text-editor/angular-node-views/text-field-component-extension.ts
new file mode 100644
index 0000000000000000000000000000000000000000..26104be7ab0a9b7b1fb7805ceccf8ddfd8a68a85
--- /dev/null
+++ b/projects/editor/src/app/text-editor/angular-node-views/text-field-component-extension.ts
@@ -0,0 +1,33 @@
+import { Injector } from '@angular/core';
+import { Node, mergeAttributes } from '@tiptap/core';
+import { AngularNodeViewRenderer } from 'ngx-tiptap';
+import { TextFieldNodeviewComponent } from './text-field-nodeview.component';
+import { TextFieldSimpleElement } from '../../../../../common/ui-elements/textfield-simple/text-field-simple-element';
+
+const TextFieldComponentExtension = (injector: Injector): Node => {
+  return Node.create({
+    group: 'inline',
+    inline: true,
+    name: 'TextField',
+
+    addAttributes() {
+      return {
+        model: {
+          default: new TextFieldSimpleElement({ type: 'text-field' })
+        }
+      };
+    },
+
+    parseHTML() {
+      return [{ tag: 'app-nodeview-text-field' }];
+    },
+    renderHTML({ HTMLAttributes }) {
+      return ['app-nodeview-text-field', mergeAttributes(HTMLAttributes)];
+    },
+    addNodeView() {
+      return AngularNodeViewRenderer(TextFieldNodeviewComponent, { injector });
+    }
+  });
+};
+
+export default TextFieldComponentExtension;
diff --git a/projects/editor/src/app/text-editor/angular-node-views/text-field-nodeview.component.ts b/projects/editor/src/app/text-editor/angular-node-views/text-field-nodeview.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8189794c3ce1861db5e2ea8a08b4ab47637f81ae
--- /dev/null
+++ b/projects/editor/src/app/text-editor/angular-node-views/text-field-nodeview.component.ts
@@ -0,0 +1,13 @@
+import { Component } from '@angular/core';
+import { AngularNodeViewComponent } from 'ngx-tiptap';
+
+@Component({
+  selector: 'app-nodeview-text-field',
+  template: `
+    <app-text-field-simple [style.display]="'inline-block'"
+                           [elementModel]="node.attrs.model"
+                           [matTooltip]="'ID: ' + node.attrs.model.id">
+    </app-text-field-simple>
+  `
+})
+export class TextFieldNodeviewComponent extends AngularNodeViewComponent { }
diff --git a/projects/editor/src/app/text-editor/angular-node-views/toggle-button-component-extension.ts b/projects/editor/src/app/text-editor/angular-node-views/toggle-button-component-extension.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c0821f9d02c536171cac756aa7937b72bb4ed86d
--- /dev/null
+++ b/projects/editor/src/app/text-editor/angular-node-views/toggle-button-component-extension.ts
@@ -0,0 +1,35 @@
+import { Injector } from '@angular/core';
+import { Node, mergeAttributes } from '@tiptap/core';
+import { AngularNodeViewRenderer } from 'ngx-tiptap';
+
+import { ToggleButtonNodeviewComponent } from './toggle-button-nodeview.component';
+import { DropListSimpleElement } from '../../../../../common/ui-elements/drop-list-simple/drop-list-simple';
+import { ToggleButtonElement } from '../../../../../common/ui-elements/toggle-button/toggle-button';
+
+const ToggleButtonComponentExtension = (injector: Injector): Node => {
+  return Node.create({
+    group: 'inline',
+    inline: true,
+    name: 'ToggleButton',
+
+    addAttributes() {
+      return {
+        model: {
+          default: new ToggleButtonElement({ type: 'toggle-button' })
+        }
+      };
+    },
+
+    parseHTML() {
+      return [{ tag: 'app-nodeview-toggle-button' }];
+    },
+    renderHTML({ HTMLAttributes }) {
+      return ['app-nodeview-toggle-button', mergeAttributes(HTMLAttributes)];
+    },
+    addNodeView() {
+      return AngularNodeViewRenderer(ToggleButtonNodeviewComponent, { injector });
+    }
+  });
+};
+
+export default ToggleButtonComponentExtension;
diff --git a/projects/editor/src/app/text-editor/angular-node-views/toggle-button-nodeview.component.ts b/projects/editor/src/app/text-editor/angular-node-views/toggle-button-nodeview.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8004c05340237d2d2aa51fba0fd19850c6f6f72b
--- /dev/null
+++ b/projects/editor/src/app/text-editor/angular-node-views/toggle-button-nodeview.component.ts
@@ -0,0 +1,13 @@
+import { Component } from '@angular/core';
+import { AngularNodeViewComponent } from 'ngx-tiptap';
+
+@Component({
+  selector: 'app-nodeview-toggle-button',
+  template: `
+    <app-toggle-button [style.display]="'inline-block'"
+                       [elementModel]="node.attrs.model"
+                       [matTooltip]="'ID: ' + node.attrs.model.id">
+    </app-toggle-button>
+  `
+})
+export class ToggleButtonNodeviewComponent extends AngularNodeViewComponent { }
diff --git a/projects/editor/src/app/text-editor/bulletList-extension.ts b/projects/editor/src/app/text-editor/extensions/bullet-list.ts
similarity index 94%
rename from projects/editor/src/app/text-editor/bulletList-extension.ts
rename to projects/editor/src/app/text-editor/extensions/bullet-list.ts
index cb37f6fdf61e887ddef7b45a9a8224d6ee9811f0..54cd0538cf8d86949e636e174faf89b34d3bad1e 100644
--- a/projects/editor/src/app/text-editor/bulletList-extension.ts
+++ b/projects/editor/src/app/text-editor/extensions/bullet-list.ts
@@ -10,7 +10,9 @@ declare module '@tiptap/core' {
   }
 }
 
-export const bulletListExtension = BulletList.extend({
+export const BulletListExtension = BulletList.extend({
+  name: 'BulletListExtension',
+
   addAttributes() {
     return {
       listStyle: {
diff --git a/projects/editor/src/app/text-editor/font-size-extension.ts b/projects/editor/src/app/text-editor/extensions/font-size.ts
similarity index 88%
rename from projects/editor/src/app/text-editor/font-size-extension.ts
rename to projects/editor/src/app/text-editor/extensions/font-size.ts
index 94bcdaeb73e5c30ae4c9a9ca65102fefbaaf7516..098ced8b2b7a374c5fc8c14dfaedf7530255f91a 100644
--- a/projects/editor/src/app/text-editor/font-size-extension.ts
+++ b/projects/editor/src/app/text-editor/extensions/font-size.ts
@@ -9,7 +9,9 @@ declare module '@tiptap/core' {
   }
 }
 
-export const fontSizeExtension = TextStyle.extend({
+export const FontSizeExtension = TextStyle.extend({
+  name: 'FontSizeExtension',
+
   addAttributes() {
     return {
       fontSize: {
diff --git a/projects/editor/src/app/text-editor/hanging-indent.ts b/projects/editor/src/app/text-editor/extensions/hanging-indent.ts
similarity index 97%
rename from projects/editor/src/app/text-editor/hanging-indent.ts
rename to projects/editor/src/app/text-editor/extensions/hanging-indent.ts
index 428922d58a913b33b331647677af53a8c6e97698..7442817b58266280d3a3abfc4150bd69b6f7ca01 100644
--- a/projects/editor/src/app/text-editor/hanging-indent.ts
+++ b/projects/editor/src/app/text-editor/extensions/hanging-indent.ts
@@ -13,8 +13,10 @@ declare module '@tiptap/core' {
 export const HangingIndent = Extension.create({
   name: 'hangingIndent',
 
-  defaultOptions: {
-    types: ['paragraph']
+  addOptions() {
+    return {
+      types: ['paragraph']
+    };
   },
 
   addGlobalAttributes() {
diff --git a/projects/editor/src/app/text-editor/indent.ts b/projects/editor/src/app/text-editor/extensions/indent.ts
similarity index 96%
rename from projects/editor/src/app/text-editor/indent.ts
rename to projects/editor/src/app/text-editor/extensions/indent.ts
index 6d2e196766a32a5a809837168553e8c10f5db539..7db3b07dbfa7873626154ae432a58918bf11ec13 100644
--- a/projects/editor/src/app/text-editor/indent.ts
+++ b/projects/editor/src/app/text-editor/extensions/indent.ts
@@ -19,10 +19,12 @@ declare module '@tiptap/core' {
 export const Indent = Extension.create<IndentOptions>({
   name: 'indent',
 
-  defaultOptions: {
-    types: ['listItem', 'paragraph'],
-    minLevel: 0,
-    maxLevel: 8
+  addOptions() {
+    return {
+      types: ['listItem', 'paragraph'],
+      minLevel: 0,
+      maxLevel: 8
+    };
   },
 
   addGlobalAttributes() {
diff --git a/projects/editor/src/app/text-editor/orderedList-extension.ts b/projects/editor/src/app/text-editor/extensions/orderedList-extension.ts
similarity index 95%
rename from projects/editor/src/app/text-editor/orderedList-extension.ts
rename to projects/editor/src/app/text-editor/extensions/orderedList-extension.ts
index cffc604f3da33645b7d92137cd0c0f401b0ce705..a410c265d08a5b493f218350787bff88aa7266f9 100644
--- a/projects/editor/src/app/text-editor/orderedList-extension.ts
+++ b/projects/editor/src/app/text-editor/extensions/orderedList-extension.ts
@@ -10,7 +10,9 @@ declare module '@tiptap/core' {
   }
 }
 
-export const orderedListExtension = OrderedList.extend({
+export const OrderedListExtension = OrderedList.extend({
+  name: 'OrderedListExtension',
+
   addAttributes() {
     return {
       listStyle: {
diff --git a/projects/editor/src/app/text-editor/paragraph-extension.ts b/projects/editor/src/app/text-editor/extensions/paragraph-extension.ts
similarity index 96%
rename from projects/editor/src/app/text-editor/paragraph-extension.ts
rename to projects/editor/src/app/text-editor/extensions/paragraph-extension.ts
index 52415f312937196e2506895b343ec587cbcad506..ca9a2578639c0f53c98dbc14d437aeaa8c4d6765 100644
--- a/projects/editor/src/app/text-editor/paragraph-extension.ts
+++ b/projects/editor/src/app/text-editor/extensions/paragraph-extension.ts
@@ -10,7 +10,7 @@ declare module '@tiptap/core' {
   }
 }
 
-export const customParagraph = Paragraph.extend({
+export const ParagraphExtension = Paragraph.extend({
   addAttributes() {
     return {
       margin: {
diff --git a/projects/editor/src/app/text-editor/rich-text-editor.component.html b/projects/editor/src/app/text-editor/rich-text-editor.component.html
index 0427a567a69db91e5ce3539c02cab5ad44b261ad..fc2106386606e119791e91bb02844778ad3c16f9 100644
--- a/projects/editor/src/app/text-editor/rich-text-editor.component.html
+++ b/projects/editor/src/app/text-editor/rich-text-editor.component.html
@@ -246,22 +246,23 @@
       <mat-icon>format_quote</mat-icon>
     </button>
   </div>
-  <div *ngIf="showCloseElements" fxLayout="row" fxLayoutAlign="space-around center" >
-    <button mat-icon-button matTooltip="Eingabefeld (\i)" [matTooltipShowDelay]="300"
-            (click)="insertSpecialChar('\\i')">
+  <div *ngIf="clozeMode" fxLayout="row" fxLayoutAlign="space-around center" >
+    <button mat-icon-button matTooltip="Eingabefeld" [matTooltipShowDelay]="300"
+            (click)="insertTextField()">
       <mat-icon>text_fields</mat-icon>
     </button>
-    <button mat-icon-button matTooltip="Ablegefeld (\z)" [matTooltipShowDelay]="300"
-            (click)="insertSpecialChar('\\z')">
+    <button mat-icon-button matTooltip="Ablegeliste" [matTooltipShowDelay]="300"
+            (click)="insertDropList()">
       <mat-icon>drag_indicator</mat-icon>
     </button>
-    <button mat-icon-button matTooltip="Optionsfeld (\r)" [matTooltipShowDelay]="300"
-            (click)="insertSpecialChar('\\r')">
+    <button mat-icon-button matTooltip="Optionsfeld" [matTooltipShowDelay]="300"
+            (click)="insertToggleButton()">
       <mat-icon>radio_button_checked</mat-icon>
     </button>
   </div>
 </div>
-<tiptap-editor [editor]="editor" [ngModel]="text"
+<tiptap-editor [editor]="editor" [ngModel]="content"
+               [outputFormat]="clozeMode ? 'json' : 'html'"
                [style.font-size.px]="defaultFontSize"
-               (ngModelChange)="textChange.emit($event)">
+               (ngModelChange)="contentChange.emit($event)">
 </tiptap-editor>
diff --git a/projects/editor/src/app/text-editor/rich-text-editor.component.ts b/projects/editor/src/app/text-editor/rich-text-editor.component.ts
index e0038ceb306611345e19b666e42a150df96cf901..29dca96a34053d27cb01cecd6f4c1a0c4d8b2787 100644
--- a/projects/editor/src/app/text-editor/rich-text-editor.component.ts
+++ b/projects/editor/src/app/text-editor/rich-text-editor.component.ts
@@ -1,6 +1,6 @@
 import {
   Component, EventEmitter, Input, Output, ViewEncapsulation,
-  AfterViewInit
+  AfterViewInit, Injector
 } from '@angular/core';
 import { Editor } from '@tiptap/core';
 import StarterKit from '@tiptap/starter-kit';
@@ -14,14 +14,20 @@ import { TextAlign } from '@tiptap/extension-text-align';
 import { Heading } from '@tiptap/extension-heading';
 import { Image } from '@tiptap/extension-image';
 import { Blockquote } from '@tiptap/extension-blockquote';
-import { Indent } from './indent';
-import { HangingIndent } from './hanging-indent';
-import { customParagraph } from './paragraph-extension';
-import { fontSizeExtension } from './font-size-extension';
-import { bulletListExtension } from './bulletList-extension';
-import { orderedListExtension } from './orderedList-extension';
+import { Indent } from './extensions/indent';
+import { HangingIndent } from './extensions/hanging-indent';
+import { ParagraphExtension } from './extensions/paragraph-extension';
+import { FontSizeExtension } from './extensions/font-size';
+import { BulletListExtension } from './extensions/bullet-list';
+import { OrderedListExtension } from './extensions/orderedList-extension';
+
 import { FileService } from '../services/file.service';
 
+import ToggleButtonComponentExtension from './angular-node-views/toggle-button-component-extension';
+import DropListComponentExtension from './angular-node-views/drop-list-component-extension';
+import TextFieldComponentExtension from './angular-node-views/text-field-component-extension';
+import { ClozeDocument } from '../../../../common/models/uI-element';
+
 @Component({
   selector: 'app-rich-text-editor',
   templateUrl: './rich-text-editor.component.html',
@@ -29,10 +35,10 @@ import { FileService } from '../services/file.service';
   encapsulation: ViewEncapsulation.None
 })
 export class RichTextEditorComponent implements AfterViewInit {
-  @Input() text!: string;
+  @Input() content!: string | Record<string, any>;
   @Input() defaultFontSize!: number;
-  @Input() showCloseElements: boolean | undefined = false;
-  @Output() textChange = new EventEmitter<string>();
+  @Input() clozeMode: boolean = false;
+  @Output() contentChange = new EventEmitter<string | Record<string, any>>();
 
   selectedFontColor = 'lightgrey';
   selectedHighlightColor = 'lightgrey';
@@ -58,10 +64,10 @@ export class RichTextEditorComponent implements AfterViewInit {
       Heading.configure({
         levels: [1, 2, 3, 4]
       }),
-      customParagraph,
-      fontSizeExtension,
-      bulletListExtension,
-      orderedListExtension,
+      ParagraphExtension,
+      FontSizeExtension,
+      BulletListExtension,
+      OrderedListExtension,
       HangingIndent,
       Image.configure({
         inline: true,
@@ -69,10 +75,15 @@ export class RichTextEditorComponent implements AfterViewInit {
           style: 'display: inline-block; height: 1em; vertical-align: middle'
         }
       }),
-      Blockquote
+      Blockquote,
+      ToggleButtonComponentExtension(this.injector),
+      DropListComponentExtension(this.injector),
+      TextFieldComponentExtension(this.injector)
     ]
   });
 
+  constructor(private injector: Injector) { }
+
   ngAfterViewInit(): void {
     this.editor.commands.focus();
   }
@@ -186,4 +197,19 @@ export class RichTextEditorComponent implements AfterViewInit {
   toggleBlockquote(): void {
     this.editor.commands.toggleBlockquote();
   }
+
+  insertToggleButton(): void {
+    this.editor.commands.insertContent('<app-nodeview-toggle-button></app-nodeview-toggle-button>');
+    this.editor.commands.focus();
+  }
+
+  insertDropList(): void {
+    this.editor.commands.insertContent('<app-nodeview-drop-list></app-nodeview-drop-list>');
+    this.editor.commands.focus();
+  }
+
+  insertTextField(): void {
+    this.editor.commands.insertContent('<app-nodeview-text-field></app-nodeview-text-field>');
+    this.editor.commands.focus();
+  }
 }
diff --git a/projects/editor/src/app/util/cloze-parser.ts b/projects/editor/src/app/util/cloze-parser.ts
index 9a7d75cf5417262124c3da5add0203acf9dcd85f..7805dcd3e964f664a8a114485b506d0059c07637 100644
--- a/projects/editor/src/app/util/cloze-parser.ts
+++ b/projects/editor/src/app/util/cloze-parser.ts
@@ -1,109 +1,32 @@
-import { InputElement, UIElement, ClozePart } from '../../../../common/models/uI-element';
+import { ClozeDocument, InputElement, UIElement } from '../../../../common/models/uI-element';
+import { IdService } from '../services/id.service';
 import { TextFieldSimpleElement } from '../../../../common/ui-elements/textfield-simple/text-field-simple-element';
-import { TextFieldElement } from '../../../../common/ui-elements/text-field/text-field-element';
-import { TextAreaElement } from '../../../../common/ui-elements/text-area/text-area-element';
-import { CheckboxElement } from '../../../../common/ui-elements/checkbox/checkbox-element';
-import { DropdownElement } from '../../../../common/ui-elements/dropdown/dropdown-element';
 import { DropListSimpleElement } from '../../../../common/ui-elements/drop-list-simple/drop-list-simple';
 import { ToggleButtonElement } from '../../../../common/ui-elements/toggle-button/toggle-button';
-import { IdService } from '../services/id.service';
 
 export abstract class ClozeParser {
-  static createClozeParts(htmlText: string, idService: IdService): ClozePart[][] {
-    const elementList = ClozeParser.createElementList(htmlText);
-
-    const parts: ClozePart[][] = [];
-    elementList.forEach((element: HTMLParagraphElement | HTMLHeadingElement, i: number) => {
-      ClozeParser.parseParagraphs(element, i, parts, idService);
-    });
-    return parts;
-  }
-
-  private static createElementList(htmlText: string): (HTMLParagraphElement | HTMLHeadingElement)[] {
-    const el = document.createElement('html');
-    el.innerHTML = htmlText;
-    return Array.from(el.children[1].children) as (HTMLParagraphElement | HTMLHeadingElement)[];
-  }
-
-  // TODO refactor passed parts, so the Part is returned instead if manipulating the param array
-  private static parseParagraphs(
-    element: HTMLParagraphElement | HTMLHeadingElement, partIndex: number, parts: ClozePart[][], idService: IdService
-  ): ClozePart[][] {
-    parts[partIndex] = [];
-    let [nextSpecialElementIndex, nextElementType] = ClozeParser.getNextElementMarker(element.innerHTML);
-    let indexOffset = 0;
-
-    while (nextSpecialElementIndex !== -1) {
-      nextSpecialElementIndex += indexOffset;
-      parts[partIndex].push({
-        type: element.localName,
-        value: element.innerHTML.substring(indexOffset, nextSpecialElementIndex),
-        style: element.style.cssText
+  static setMissingIDs(clozeJSON: ClozeDocument, idService: IdService): ClozeDocument {
+    clozeJSON.content.forEach((paragraph: any) => {
+      paragraph.content?.forEach((node: any) => {
+        if (['ToggleButton', 'DropList', 'TextField'].includes(node.type) &&
+            node.attrs.model.id === 'id_placeholder') {
+          // create element anew because the TextEditor can't create multiple element instances
+          node.attrs.model = ClozeParser.createElement(node.attrs.model);
+          node.attrs.model.id = idService.getNewID(node.attrs.model.type);
+        }
       });
-
-      const newElement = ClozeParser.createElement({ type: nextElementType } as UIElement, idService);
-      parts[partIndex].push({ type: nextElementType, value: newElement });
-
-      indexOffset = nextSpecialElementIndex + 2; // + 2 to get rid of the marker, i.e. '\b'
-      [nextSpecialElementIndex, nextElementType] =
-        ClozeParser.getNextElementMarker(element.innerHTML.substring(indexOffset));
-    }
-    parts[partIndex].push({
-      type: element.localName,
-      value: element.innerHTML.substring(indexOffset),
-      style: element.style.cssText
     });
-    return parts;
+    return clozeJSON;
   }
 
-  private static getNextElementMarker(p: string): [number, string] {
-    const x = [];
-    if (p.indexOf('\\d') > 0) {
-      x.push(p.indexOf('\\d'));
-    }
-    if (p.indexOf('\\i') > 0) {
-      x.push(p.indexOf('\\i'));
-    }
-    if (p.indexOf('\\z') > 0) {
-      x.push(p.indexOf('\\z'));
-    }
-    if (p.indexOf('\\r') > 0) {
-      x.push(p.indexOf('\\r'));
-    }
-
-    const y = Math.min(...x);
-    let nextElementType = '';
-    switch (p[y + 1]) {
-      case 'd': nextElementType = 'dropdown'; break;
-      case 'i': nextElementType = 'text-field'; break;
-      case 'z': nextElementType = 'drop-list'; break;
-      case 'r': nextElementType = 'toggle-button'; break;
-      default: return [-1, 'unknown'];
-    }
-    return [y, nextElementType];
-  }
-
-  private static createElement(elementModel: Partial<UIElement>, idService: IdService): InputElement {
+  private static createElement(elementModel: Partial<UIElement>): InputElement {
     let newElement: InputElement;
-    elementModel.id = idService.getNewID(elementModel.type as string);
     switch (elementModel.type) {
       case 'text-field':
         newElement = new TextFieldSimpleElement(elementModel);
-        (newElement as TextFieldElement).label = '';
-        break;
-      case 'text-area':
-        newElement = new TextAreaElement(elementModel);
-        break;
-      case 'checkbox':
-        newElement = new CheckboxElement(elementModel);
-        break;
-      case 'dropdown':
-        newElement = new DropdownElement(elementModel);
         break;
       case 'drop-list':
         newElement = new DropListSimpleElement(elementModel);
-        newElement.height = 25; // TODO weg?
-        newElement.width = 100;
         break;
       case 'toggle-button':
         newElement = new ToggleButtonElement(elementModel);