,
+        composerFunctions: ComposerFunctions,
+    ) => ReactNode;
+}
+
+export function PlainTextComposer({ className, disabled, onSend, onChange, children }: PlainTextComposerProps) {
+   const {ref, onInput, onPaste, onKeyDown} = usePlainTextListeners(onChange, onSend)
+   const composerFunctions = useComposerFunctions(ref)
+
+    return 
+        
+        {children?.(ref, composerFunctions)}
+    
;
+}
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.tsx b/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.tsx
new file mode 100644
index 0000000000..99a89589ee
--- /dev/null
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.tsx
@@ -0,0 +1,27 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { RefObject, useMemo } from "react";
+
+export function useComposerFunctions(ref: RefObject) {
+    return useMemo(() => ({
+        clear: () => {
+            if (ref.current) {
+                ref.current.innerHTML = '';
+            }
+        },
+    }), [ref]);
+}
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts
index 414b6df45c..06839ab262 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts
@@ -20,7 +20,7 @@ import { useCallback } from "react";
 import { useSettingValue } from "../../../../../hooks/useSettings";
 
 export function useInputEventProcessor(onSend: () => void) {
-    const isCtrlEnter = useSettingValue("MessageComposerInput.ctrlEnterToSend") as boolean;
+    const isCtrlEnter = useSettingValue("MessageComposerInput.ctrlEnterToSend");
     return useCallback((event: WysiwygInputEvent) => {
         if (event instanceof ClipboardEvent) {
             return event;
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.tsx b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.tsx
new file mode 100644
index 0000000000..98d09c12b0
--- /dev/null
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.tsx
@@ -0,0 +1,50 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { KeyboardEvent, SyntheticEvent, useCallback, useRef } from "react";
+
+import { useInputEventProcessor } from "./useInputEventProcessor";
+
+function isDivElement(target: EventTarget): target is HTMLDivElement {
+    return target instanceof HTMLDivElement;
+}
+
+export function usePlainTextListeners(onChange: (content: string) => void, onSend: () => void) {
+    const ref = useRef();
+    const send = useCallback((() => {
+        if (ref.current) {
+            ref.current.innerText = '';
+        }
+        onSend();
+    }), [ref, onSend]);
+
+    const inputEventProcessor = useInputEventProcessor(send);
+
+    const onInput = useCallback((event: SyntheticEvent) => {
+        if (isDivElement(event.target)) {
+            onChange(event.target.innerText);
+        }
+        inputEventProcessor(event.nativeEvent);
+    }, [onChange, inputEventProcessor]);
+
+    const onKeyDown = useCallback((event: KeyboardEvent) => {
+        if (event.key === 'Enter') {
+            send();
+        }
+    }, [send]);
+
+    return { ref, onInput, onPaste: onInput, onKeyDown };
+}
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygSendActionHandler.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygSendActionHandler.ts
index b7c18f19c2..49c6302d5b 100644
--- a/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygSendActionHandler.ts
+++ b/src/components/views/rooms/wysiwyg_composer/hooks/useWysiwygSendActionHandler.ts
@@ -15,7 +15,6 @@ limitations under the License.
 */
 
 import { RefObject, useCallback, useRef } from "react";
-import { FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
 
 import defaultDispatcher from "../../../../../dispatcher/dispatcher";
 import { Action } from "../../../../../dispatcher/actions";
@@ -23,11 +22,12 @@ import { ActionPayload } from "../../../../../dispatcher/payloads";
 import { TimelineRenderingType, useRoomContext } from "../../../../../contexts/RoomContext";
 import { useDispatcher } from "../../../../../hooks/useDispatcher";
 import { focusComposer } from "./utils";
+import { ComposerFunctions } from "../types";
 
 export function useWysiwygSendActionHandler(
     disabled: boolean,
     composerElement: RefObject,
-    wysiwyg: FormattingFunctions,
+    composerFunctions: ComposerFunctions,
 ) {
     const roomContext = useRoomContext();
     const timeoutId = useRef();
@@ -45,12 +45,12 @@ export function useWysiwygSendActionHandler(
                 focusComposer(composerElement, context, roomContext, timeoutId);
                 break;
             case Action.ClearAndFocusSendMessageComposer:
-                wysiwyg.clear();
+                composerFunctions.clear();
                 focusComposer(composerElement, context, roomContext, timeoutId);
                 break;
             // TODO: case Action.ComposerInsert: - see SendMessageComposer
         }
-    }, [disabled, composerElement, wysiwyg, timeoutId, roomContext]);
+    }, [disabled, composerElement, composerFunctions, timeoutId, roomContext]);
 
     useDispatcher(defaultDispatcher, handler);
 }
diff --git a/src/components/views/rooms/wysiwyg_composer/types.ts b/src/components/views/rooms/wysiwyg_composer/types.ts
new file mode 100644
index 0000000000..96095abebf
--- /dev/null
+++ b/src/components/views/rooms/wysiwyg_composer/types.ts
@@ -0,0 +1,19 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+export type ComposerFunctions = {
+    clear: () => void;
+};
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts b/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts
index cc0d2235bf..df42b0062b 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts
@@ -16,6 +16,8 @@ limitations under the License.
 
 import { IContent, IEventRelation, MatrixEvent, MsgType } from "matrix-js-sdk/src/matrix";
 
+import { htmlSerializeFromMdIfNeeded } from "../../../../../editor/serialize";
+import SettingsStore from "../../../../../settings/SettingsStore";
 import { RoomPermalinkCreator } from "../../../../../utils/permalinks/Permalinks";
 import { addReplyToMessageContent } from "../../../../../utils/Reply";
 
@@ -39,6 +41,19 @@ function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
     return (mxReply && mxReply.outerHTML) || "";
 }
 
+function getTextReplyFallback(mxEvent: MatrixEvent): string {
+    const body = mxEvent.getContent().body;
+    const lines = body.split("\n").map(l => l.trim());
+    if (lines.length > 2 && lines[0].startsWith("> ") && lines[1].length === 0) {
+        return `${lines[0]}\n\n`;
+    }
+    return "";
+}
+
+function htmlToPlainText(html: string) {
+    return new DOMParser().parseFromString(html, 'text/html').documentElement.textContent;
+}
+
 interface CreateMessageContentParams {
     relation?: IEventRelation;
     replyToEvent?: MatrixEvent;
@@ -49,6 +64,7 @@ interface CreateMessageContentParams {
 
 export function createMessageContent(
     message: string,
+    isHTML: boolean,
     { relation, replyToEvent, permalinkCreator, includeReplyLegacyFallback = true, editedEvent }:
     CreateMessageContentParams,
 ): IContent {
@@ -56,6 +72,7 @@ export function createMessageContent(
 
     const isEditing = Boolean(editedEvent);
     const isReply = isEditing ? Boolean(editedEvent?.replyEventId) : Boolean(replyToEvent);
+    const isReplyAndEditing = isEditing && isReply;
 
     /*const isEmote = containsEmote(model);
     if (isEmote) {
@@ -67,37 +84,43 @@ export function createMessageContent(
     model = unescapeMessage(model);*/
 
     // const body = textSerialize(model);
-    const body = message;
+
+    const body = isHTML && htmlToPlainText(message) || message;
+    const bodyPrefix = isReplyAndEditing && getTextReplyFallback(editedEvent) || '';
+    const formattedBodyPrefix = isReplyAndEditing && getHtmlReplyFallback(editedEvent) || '';
 
     const content: IContent = {
         // TODO emote
-    //    msgtype: isEmote ? "m.emote" : "m.text",
         msgtype: MsgType.Text,
-        body: body,
+        // TODO when available, use HTML --> Plain text conversion from wysiwyg rust model
+        body: isEditing ? `${bodyPrefix} * ${body}` : body,
     };
 
     // TODO markdown support
 
-    /*const formattedBody = htmlSerializeIfNeeded(model, {
-        forceHTML: !!replyToEvent,
-        useMarkdown: SettingsStore.getValue("MessageComposerInput.useMarkdown"),
-    });*/
-    const formattedBody = message;
+    const isMarkdownEnabled = SettingsStore.getValue("MessageComposerInput.useMarkdown");
+    const formattedBody =
+        isHTML ?
+            message :
+            isMarkdownEnabled ?
+                htmlSerializeFromMdIfNeeded(message, { forceHTML: isReply }) :
+                null;
 
     if (formattedBody) {
         content.format = "org.matrix.custom.html";
-
-        const htmlPrefix = isReply && isEditing ? getHtmlReplyFallback(editedEvent) : '';
-        content.formatted_body = isEditing ? `${htmlPrefix} * ${formattedBody}` : formattedBody;
+        content.formatted_body = isEditing ? `${formattedBodyPrefix} * ${formattedBody}` : formattedBody;
     }
 
     if (isEditing) {
         content['m.new_content'] = {
             "msgtype": content.msgtype,
             "body": body,
-            "format": "org.matrix.custom.html",
-            'formatted_body': formattedBody,
         };
+
+        if (formattedBody) {
+            content['m.new_content'].format = "org.matrix.custom.html";
+            content['m.new_content']['formatted_body'] = formattedBody;
+        }
     }
 
     const newRelation = isEditing ?
diff --git a/src/components/views/rooms/wysiwyg_composer/utils/message.ts b/src/components/views/rooms/wysiwyg_composer/utils/message.ts
index dbea29c848..d84392c18e 100644
--- a/src/components/views/rooms/wysiwyg_composer/utils/message.ts
+++ b/src/components/views/rooms/wysiwyg_composer/utils/message.ts
@@ -44,7 +44,8 @@ interface SendMessageParams {
 }
 
 export function sendMessage(
-    html: string,
+    message: string,
+    isHTML: boolean,
     { roomContext, mxClient, ...params }: SendMessageParams,
 ) {
     const { relation, replyToEvent } = params;
@@ -76,7 +77,8 @@ export function sendMessage(
 
     if (!content) {
         content = createMessageContent(
-            html,
+            message,
+            isHTML,
             params,
         );
     }
@@ -167,7 +169,7 @@ export function editMessage(
         const position = this.model.positionForOffset(caret.offset, caret.atNodeEnd);
         this.editorRef.current?.replaceEmoticon(position, REGEX_EMOTICON);
     }*/
-    const editContent = createMessageContent(html, { editedEvent });
+    const editContent = createMessageContent(html, true, { editedEvent });
     const newContent = editContent["m.new_content"];
 
     const shouldSend = true;
diff --git a/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx b/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx
index 72fd52be57..051d25b435 100644
--- a/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx
+++ b/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx
@@ -163,7 +163,7 @@ describe('EditWysiwygComposer', () => {
 
             // Then
             const expectedContent = {
-                "body": mockContent,
+                "body": ` * ${mockContent}`,
                 "format": "org.matrix.custom.html",
                 "formatted_body": ` * ${mockContent}`,
                 "m.new_content": {
diff --git a/test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx b/test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx
index 20148b802a..c97e5e9086 100644
--- a/test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx
+++ b/test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx
@@ -72,7 +72,7 @@ describe('SendWysiwygComposer', () => {
         return render(
             
                 
-                    
+                    
                 
             ,
         );
diff --git a/test/components/views/rooms/wysiwyg_composer/utils/createMessageContent-test.ts b/test/components/views/rooms/wysiwyg_composer/utils/createMessageContent-test.ts
index a4335b2bf1..4c7028749c 100644
--- a/test/components/views/rooms/wysiwyg_composer/utils/createMessageContent-test.ts
+++ b/test/components/views/rooms/wysiwyg_composer/utils/createMessageContent-test.ts
@@ -40,11 +40,11 @@ describe('createMessageContent', () => {
 
     it("Should create html message", () => {
         // When
-        const content = createMessageContent(message, { permalinkCreator });
+        const content = createMessageContent(message, true, { permalinkCreator });
 
         // Then
         expect(content).toEqual({
-            "body": message,
+            "body": "hello world",
             "format": "org.matrix.custom.html",
             "formatted_body": message,
             "msgtype": "m.text",
@@ -53,11 +53,11 @@ describe('createMessageContent', () => {
 
     it('Should add reply to message content', () => {
         // When
-        const content = createMessageContent(message, { permalinkCreator, replyToEvent: mockEvent });
+        const content = createMessageContent(message, true, { permalinkCreator, replyToEvent: mockEvent });
 
         // Then
         expect(content).toEqual({
-            "body": ">  Replying to this\n\nhello world",
+            "body": ">  Replying to this\n\nhello world",
             "format": "org.matrix.custom.html",
             "formatted_body": "In reply to" +
                                     " myfakeuser"+
@@ -77,11 +77,11 @@ describe('createMessageContent', () => {
             rel_type: "m.thread",
             event_id: "myFakeThreadId",
         };
-        const content = createMessageContent(message, { permalinkCreator, relation });
+        const content = createMessageContent(message, true, { permalinkCreator, relation });
 
         // Then
         expect(content).toEqual({
-            "body": message,
+            "body": "hello world",
             "format": "org.matrix.custom.html",
             "formatted_body": message,
             "msgtype": "m.text",
@@ -110,16 +110,16 @@ describe('createMessageContent', () => {
             event: true,
         });
         const content =
-                createMessageContent(message, { permalinkCreator, editedEvent });
+                createMessageContent(message, true, { permalinkCreator, editedEvent });
 
         // Then
         expect(content).toEqual({
-            "body": message,
+            "body": " * hello world",
             "format": "org.matrix.custom.html",
             "formatted_body": ` * ${message}`,
             "msgtype": "m.text",
             "m.new_content": {
-                "body": message,
+                "body": "hello world",
                 "format": "org.matrix.custom.html",
                 "formatted_body": message,
                 "msgtype": "m.text",
diff --git a/test/components/views/rooms/wysiwyg_composer/utils/message-test.ts b/test/components/views/rooms/wysiwyg_composer/utils/message-test.ts
index 9d13f28176..0829b19adb 100644
--- a/test/components/views/rooms/wysiwyg_composer/utils/message-test.ts
+++ b/test/components/views/rooms/wysiwyg_composer/utils/message-test.ts
@@ -65,7 +65,7 @@ describe('message', () => {
     describe('sendMessage', () => {
         it('Should not send empty html message', async () => {
             // When
-            await sendMessage('', { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator });
+            await sendMessage('', true, { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator });
 
             // Then
             expect(mockClient.sendMessage).toBeCalledTimes(0);
@@ -74,11 +74,15 @@ describe('message', () => {
 
         it('Should send html message', async () => {
             // When
-            await sendMessage(message, { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator });
+            await sendMessage(
+                message,
+                true,
+                { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator },
+            );
 
             // Then
             const expectedContent = {
-                "body": "hello world",
+                "body": "hello world",
                 "format": "org.matrix.custom.html",
                 "formatted_body": "hello world",
                 "msgtype": "m.text",
@@ -97,7 +101,7 @@ describe('message', () => {
             });
 
             // When
-            await sendMessage(message, {
+            await sendMessage(message, true, {
                 roomContext: defaultRoomContext,
                 mxClient: mockClient,
                 permalinkCreator,
@@ -112,7 +116,7 @@ describe('message', () => {
             });
 
             const expectedContent = {
-                "body": ">  My reply\n\nhello world",
+                "body": ">  My reply\n\nhello world",
                 "format": "org.matrix.custom.html",
                 "formatted_body": "In reply to" +
                                     " myfakeuser2" +
@@ -130,7 +134,11 @@ describe('message', () => {
         it('Should scroll to bottom after sending a html message', async () => {
             // When
             SettingsStore.setValue("scrollToBottomOnMessageSent", null, SettingLevel.DEVICE, true);
-            await sendMessage(message, { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator });
+            await sendMessage(
+                message,
+                true,
+                { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator },
+            );
 
             // Then
             expect(spyDispatcher).toBeCalledWith(
@@ -140,7 +148,11 @@ describe('message', () => {
 
         it('Should handle emojis', async () => {
             // When
-            await sendMessage('🎉', { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator });
+            await sendMessage(
+                '🎉',
+                false,
+                { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator },
+            );
 
             // Then
             expect(spyDispatcher).toBeCalledWith(
@@ -203,7 +215,7 @@ describe('message', () => {
             // Then
             const { msgtype, format } = mockEvent.getContent();
             const expectedContent = {
-                "body": newMessage,
+                "body": ` * ${newMessage}`,
                 "formatted_body": ` * ${newMessage}`,
                 "m.new_content": {
                     "body": "Replying to this new content",