diff --git a/src/App.jsx b/src/App.jsx
index caecd16687bdbb4df84c5dcdad3aa49d5b1b3c37..225ee33807383ca265ee4d90afe80d939d6afbad 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -8,7 +8,8 @@ import Footer from "components/Footer";
 import Navbar from "components/Navbar";
 import Home from "pages/Home";
 import Program from "pages/Program";
-import { AuthStore } from "stores";
+import { AuthStore, PostStore } from "stores";
+import { updateWindowPosts } from "utils";
 
 import keycloak from "./keycloak";
 
@@ -26,18 +27,19 @@ if (process.env.REACT_APP_SENTRY_DSN) {
 const onKeycloakEvent = (event) => {
   if (["onAuthRefreshSuccess", "onAuthSuccess"].includes(event)) {
     Sentry.setUser(keycloak.tokenParsed);
-    AuthStore.update((state) => {
-      const kcRoles = keycloak.tokenParsed.roles;
-      let role = null;
 
-      if (kcRoles.includes("chairman")) {
-        role = "chairman";
-      } else if (kcRoles.includes("member")) {
-        role = "member";
-      } else {
-        role = "regp";
-      }
+    const kcRoles = keycloak.tokenParsed.roles;
+    let role = null;
+
+    if (kcRoles.includes("chairman")) {
+      role = "chairman";
+    } else if (kcRoles.includes("member")) {
+      role = "member";
+    } else {
+      role = "regp";
+    }
 
+    AuthStore.update((state) => {
       state.isAuthenticated = true;
       state.user = {
         name: keycloak.tokenParsed.name,
@@ -46,6 +48,12 @@ const onKeycloakEvent = (event) => {
         accessToken: keycloak.token,
       };
     });
+
+    PostStore.update((state) => {
+      // Only display proposals verified by chairman to other users.
+      state.filters.showPendingProposals = role === "chairman";
+      updateWindowPosts(state);
+    });
   }
 };
 
diff --git a/src/components/MarkdownEditor.jsx b/src/components/MarkdownEditor.jsx
deleted file mode 100644
index 1379fe5a176ad1317c57299f502a7ab0c1bd708a..0000000000000000000000000000000000000000
--- a/src/components/MarkdownEditor.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from "react";
-import ReactMde from "react-mde";
-import Showdown from "showdown";
-
-const converter = new Showdown.Converter({
-  tables: true,
-  simplifiedAutoLink: true,
-  strikethrough: true,
-  tasklists: true,
-});
-
-const MarkdownEditor = ({ value, onChange }) => {
-  return (
-    <ReactMde
-      value={value}
-      onChange={onChange}
-      // selectedTab={selectedTab}
-      // onTabChange={setSelectedTab}
-      generateMarkdownPreview={(markdown) =>
-        Promise.resolve(converter.makeHtml(markdown))
-      }
-    />
-  );
-};
-
-export default MarkdownEditor;
diff --git a/src/components/annoucements/AnnouncementEditModal.jsx b/src/components/annoucements/AnnouncementEditModal.jsx
index c0bed97aeb03f8044cdaa4ea0e78dc39de345527..69e52f1334dfb4c2f1c7b302d3b4c33ece7a5989 100644
--- a/src/components/annoucements/AnnouncementEditModal.jsx
+++ b/src/components/annoucements/AnnouncementEditModal.jsx
@@ -3,6 +3,7 @@ import React, { useState } from "react";
 import Button from "components/Button";
 import { Card, CardActions, CardBody, CardHeadline } from "components/cards";
 import ErrorMessage from "components/ErrorMessage";
+import MarkdownEditor from "components/mde/MarkdownEditor";
 import Modal from "components/modals/Modal";
 
 const AnnouncementEditModal = ({
@@ -14,19 +15,26 @@ const AnnouncementEditModal = ({
   ...props
 }) => {
   const [text, setText] = useState(announcement.content);
+  const [noTextError, setNoTextError] = useState(false);
 
-  const onTextInput = (evt) => {
-    setText(evt.target.value);
+  const onTextInput = (newText) => {
+    setText(newText);
+
+    if (newText !== "") {
+      setNoTextError(false);
+    }
   };
 
   const confirm = (evt) => {
     if (!!text) {
       onConfirm(text);
+    } else {
+      setNoTextError(true);
     }
   };
 
   return (
-    <Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}>
+    <Modal containerClassName="max-w-lg" onRequestClose={onCancel} {...props}>
       <Card>
         <CardBody>
           <div className="flex items-center justify-between mb-4">
@@ -35,20 +43,20 @@ const AnnouncementEditModal = ({
               <i className="ico--close"></i>
             </button>
           </div>
-          <div className="form-field">
-            <label className="form-field__label" htmlFor="field">
-              Nový text oznámení
-            </label>
-            <div className="form-field__wrapper form-field__wrapper--shadowed">
-              <textarea
-                className="text-input form-field__control text-base"
-                value={text}
-                rows="8"
-                placeholder="Vyplňte text oznámení"
-                onChange={onTextInput}
-              ></textarea>
-            </div>
-          </div>
+          <MarkdownEditor
+            value={text}
+            onChange={onTextInput}
+            error={
+              noTextError
+                ? "Před úpravou oznámení nezapomeňte vyplnit jeho obsah."
+                : null
+            }
+            placeholder="Vyplňte text oznámení"
+            toolbarCommands={[
+              ["bold", "italic", "strikethrough"],
+              ["link", "unordered-list", "ordered-list"],
+            ]}
+          />
           {error && (
             <ErrorMessage className="mt-2">
               Při editaci došlo k problému: {error}
diff --git a/src/components/mde/MarkdownEditor.css b/src/components/mde/MarkdownEditor.css
new file mode 100644
index 0000000000000000000000000000000000000000..970a2c9409f1b8793a59a97a7d5891fa5479d4d5
--- /dev/null
+++ b/src/components/mde/MarkdownEditor.css
@@ -0,0 +1,77 @@
+.mde-header {
+  background: transparent;
+}
+
+.react-mde .invisible {
+  display: none;
+}
+
+.mde-header {
+  border: 0;
+  align-items: center;
+}
+
+.mde-header .mde-tabs {
+  display: inline-flex;
+  background-color: #000;
+  background-color: rgba(0,0,0,1);
+  padding: .25rem;
+}
+
+.mde-header .mde-tabs button {
+  padding: .5rem 1rem;
+  font-family: Bebas Neue,Helvetica,Arial,sans-serif;
+  font-weight: 400;
+  font-size: 1.1rem;
+  --text-opacity: 1;
+  color: #fff;
+  color: rgba(255,255,255,var(--text-opacity));
+  text-align: center;
+  cursor: pointer;
+  border: 0;
+  border-radius: 0;
+  margin: 0 !important;
+  outline: 0;
+}
+
+.mde-header .mde-tabs button.selected {
+  /* blue-300 */
+  background: #027da8;
+  color: #fff;
+  border: 0;
+  border-radius: 0;
+  margin: 0;
+  outline: 0;
+}
+
+.mde-header .mde-tabs button:not(.selected):hover {
+  /* grey-500 */
+  background: #303132;
+}
+
+.mde-header .mde-header-item {
+  border: 1px transparent solid;
+  transition: border-color 100ms ease-in-out;
+}
+
+.mde-header ul.mde-header-group li.mde-header-item {
+  margin: 0;
+}
+
+.mde-header .mde-header-item:hover {
+  /* grey-200 */
+  border: 1px #adadad solid;
+}
+
+.mde-text {
+  font-family: monospace;
+}
+
+
+.mde-header ul.mde-header-group {
+  padding: 0 0.5rem;
+}
+
+.mde-header ul.mde-header-group + .mde-header-group {
+  margin-left: .5rem;
+}
diff --git a/src/components/mde/MarkdownEditor.jsx b/src/components/mde/MarkdownEditor.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..88a74fe4d50d38f0dbcea58e67d6e9bd5bc99de9
--- /dev/null
+++ b/src/components/mde/MarkdownEditor.jsx
@@ -0,0 +1,62 @@
+import React, { useState } from "react";
+import ReactMde from "react-mde";
+import classNames from "classnames";
+import Showdown from "showdown";
+
+import "react-mde/lib/styles/css/react-mde-toolbar.css";
+import "./MarkdownEditor.css";
+
+const converter = new Showdown.Converter({
+  tables: true,
+  simplifiedAutoLink: true,
+  strikethrough: true,
+  tasklists: true,
+});
+
+const MarkdownEditor = ({
+  value,
+  onChange,
+  error,
+  placeholder = "",
+  ...props
+}) => {
+  const [selectedTab, setSelectedTab] = useState("write");
+
+  const classes = {
+    preview: "content-block p-2 border border-grey-200",
+    textArea: "p-2 text-input text-base",
+  };
+
+  const l18n = {
+    write: "Psaní",
+    preview: "Náhled",
+    uploadingImage: "Nahrávám obrázek",
+  };
+
+  const childProps = {
+    textArea: {
+      placeholder,
+    },
+  };
+
+  return (
+    <div className={classNames("form-field", { "form-field--error": !!error })}>
+      <ReactMde
+        value={value}
+        onChange={onChange}
+        selectedTab={selectedTab}
+        onTabChange={setSelectedTab}
+        generateMarkdownPreview={(markdown) =>
+          Promise.resolve(converter.makeHtml(markdown))
+        }
+        classes={classes}
+        l18n={l18n}
+        childProps={childProps}
+        {...props}
+      />
+      {error && <div className="form-field__error">{error}</div>}
+    </div>
+  );
+};
+
+export default MarkdownEditor;
diff --git a/src/components/posts/PostEditModal.jsx b/src/components/posts/PostEditModal.jsx
index 72b5c0c3cdc09da0ff1c415857196c87f75977a1..d2b00e7e3f4bc9d7fdea8a290743d1e542adcae5 100644
--- a/src/components/posts/PostEditModal.jsx
+++ b/src/components/posts/PostEditModal.jsx
@@ -3,6 +3,7 @@ import React, { useState } from "react";
 import Button from "components/Button";
 import { Card, CardActions, CardBody, CardHeadline } from "components/cards";
 import ErrorMessage from "components/ErrorMessage";
+import MarkdownEditor from "components/mde/MarkdownEditor";
 import Modal from "components/modals/Modal";
 
 const PostEditModal = ({
@@ -14,19 +15,26 @@ const PostEditModal = ({
   ...props
 }) => {
   const [text, setText] = useState(post.content);
+  const [noTextError, setNoTextError] = useState(false);
 
-  const onTextInput = (evt) => {
-    setText(evt.target.value);
+  const onTextInput = (newText) => {
+    setText(newText);
+
+    if (newText !== "") {
+      setNoTextError(false);
+    }
   };
 
   const confirm = (evt) => {
     if (!!text) {
       onConfirm(text);
+    } else {
+      setNoTextError(true);
     }
   };
 
   return (
-    <Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}>
+    <Modal containerClassName="max-w-xl" onRequestClose={onCancel} {...props}>
       <Card>
         <CardBody>
           <div className="flex items-center justify-between mb-4">
@@ -35,20 +43,16 @@ const PostEditModal = ({
               <i className="ico--close"></i>
             </button>
           </div>
-          <div className="form-field">
-            <label className="form-field__label" htmlFor="field">
-              Nový text příspěvku
-            </label>
-            <div className="form-field__wrapper form-field__wrapper--shadowed">
-              <textarea
-                className="text-input form-field__control text-base"
-                value={text}
-                rows="8"
-                placeholder="Vyplňte text příspěvku"
-                onChange={onTextInput}
-              ></textarea>
-            </div>
-          </div>
+          <MarkdownEditor
+            value={text}
+            onChange={onTextInput}
+            error={
+              noTextError
+                ? "Před upravením příspěvku nezapomeňte vyplnit jeho obsah."
+                : null
+            }
+            placeholder="Vyplňte text příspěvku"
+          />
           {error && (
             <ErrorMessage className="mt-2">
               Při editaci došlo k problému: {error}
diff --git a/src/containers/AddAnnouncementForm.jsx b/src/containers/AddAnnouncementForm.jsx
index de76ab8243c9bafd5d990db62d7965898fb512a2..2a3f5fbaa750a8ca9bc080d8461af17f4577831a 100644
--- a/src/containers/AddAnnouncementForm.jsx
+++ b/src/containers/AddAnnouncementForm.jsx
@@ -4,6 +4,7 @@ import classNames from "classnames";
 import { addAnnouncement } from "actions/announcements";
 import Button from "components/Button";
 import ErrorMessage from "components/ErrorMessage";
+import MarkdownEditor from "components/mde/MarkdownEditor";
 import { useActionState } from "hooks";
 
 const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
@@ -21,10 +22,10 @@ const AddAnnouncementForm = ({ className }) => {
     type,
   });
 
-  const onTextInput = (evt) => {
-    setText(evt.target.value);
+  const onTextInput = (newText) => {
+    setText(newText);
 
-    if (evt.target.value !== "") {
+    if (newText !== "") {
       setNoTextError(false);
     }
   };
@@ -90,27 +91,21 @@ const AddAnnouncementForm = ({ className }) => {
           </div>
         </div>
 
-        <div
-          className={classNames("form-field", {
-            "form-field--error": noTextError,
-          })}
-        >
-          <div className="form-field__wrapper form-field__wrapper--shadowed">
-            <textarea
-              className="text-input text-sm form-field__control "
-              value={text}
-              rows="3"
-              cols="40"
-              placeholder="Vyplňte text oznámení"
-              onChange={onTextInput}
-            ></textarea>
-          </div>
-          {noTextError && (
-            <div className="form-field__error">
-              Před přidáním oznámení nezapomeňte vyplnit jeho obsah.
-            </div>
-          )}
-        </div>
+        <MarkdownEditor
+          value={text}
+          onChange={onTextInput}
+          error={
+            noTextError
+              ? "Před přidáním oznámení nezapomeňte vyplnit jeho obsah."
+              : null
+          }
+          placeholder="Vyplňte text oznámení"
+          toolbarCommands={[
+            ["bold", "italic", "strikethrough"],
+            ["link", "unordered-list", "ordered-list"],
+          ]}
+          minEditorHeight={100}
+        />
 
         <div
           className={classNames("form-field", {
diff --git a/src/containers/AddPostForm.jsx b/src/containers/AddPostForm.jsx
index 667278372f7f3d9b2292f89f66097261c54c4b77..2e3fedf098985ce6e59aad359fabaf2c57d3335d 100644
--- a/src/containers/AddPostForm.jsx
+++ b/src/containers/AddPostForm.jsx
@@ -1,9 +1,9 @@
 import React, { useState } from "react";
-import classNames from "classnames";
 
 import { addPost, addProposal } from "actions/posts";
 import Button from "components/Button";
 import ErrorMessage from "components/ErrorMessage";
+import MarkdownEditor from "components/mde/MarkdownEditor";
 import { useActionState } from "hooks";
 
 const AddPostForm = ({ className }) => {
@@ -17,10 +17,10 @@ const AddPostForm = ({ className }) => {
     content: text,
   });
 
-  const onTextInput = (evt) => {
-    setText(evt.target.value);
+  const onTextInput = (newText) => {
+    setText(newText);
 
-    if (evt.target.value !== "") {
+    if (newText !== "") {
       setNoTextError(false);
     }
   };
@@ -83,27 +83,16 @@ const AddPostForm = ({ className }) => {
           Při přidávání příspěvku došlo k problému: {addingProposalError}.
         </ErrorMessage>
       )}
-      <div
-        className={classNames("form-field", {
-          "form-field--error": noTextError,
-        })}
-      >
-        <div className="form-field__wrapper form-field__wrapper--shadowed">
-          <textarea
-            className="text-input form-field__control "
-            value={text}
-            rows="5"
-            cols="40"
-            placeholder="Vyplňte text vašeho příspěvku"
-            onChange={onTextInput}
-          ></textarea>
-        </div>
-        {noTextError && (
-          <div className="form-field__error">
-            Před přidáním příspěvku nezapomeňte vyplnit jeho obsah.
-          </div>
-        )}
-      </div>
+      <MarkdownEditor
+        value={text}
+        onChange={onTextInput}
+        error={
+          noTextError
+            ? "Před přidáním příspěvku nezapomeňte vyplnit jeho obsah."
+            : null
+        }
+        placeholder="Vyplňte text vašeho příspěvku"
+      />
 
       <div className="space-x-4">
         <Button
diff --git a/src/containers/PostsContainer.jsx b/src/containers/PostsContainer.jsx
index 25d968abd4b4c37682b4640b0e18ac3ddedce22c..907f7ded861132f2990675fdd292fc68705efe61 100644
--- a/src/containers/PostsContainer.jsx
+++ b/src/containers/PostsContainer.jsx
@@ -146,14 +146,7 @@ const PostsContainer = ({ className }) => {
 
   const sliceStart = (window.page - 1) * window.perPage;
   const sliceEnd = window.page * window.perPage;
-  let windowItems = window.items.map((postId) => items[postId]);
-
-  // Only display proposals verified by chairman to other users.
-  if (!user || user.role !== "chairman") {
-    windowItems = windowItems.filter(
-      (item) => item.type === "post" || item.state !== "pending"
-    );
-  }
+  const windowItems = window.items.map((postId) => items[postId]);
 
   return (
     <>
diff --git a/src/stores.js b/src/stores.js
index 6616a4f5ec9a6f9c9555e21cac12bf78ce4680b9..f4e1511b998a6e84afec4917c1608a2f1e30ad06 100644
--- a/src/stores.js
+++ b/src/stores.js
@@ -39,6 +39,7 @@ const postStoreInitial = {
     flags: "all",
     sort: "byDate",
     type: "all",
+    showPendingProposals: false,
   },
 };
 
diff --git a/src/utils.js b/src/utils.js
index 65d16be18e5e56c2511ad9ef4788049dafa1c77c..83fb40083240e42090dc552b3dd27bc12d4063f3 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -28,6 +28,12 @@ export const filterPosts = (filters, allItems) => {
 
   let filteredItems = filter(allItems, predicate);
 
+  if (!filters.showPendingProposals) {
+    filteredItems = filteredItems.filter(
+      (item) => item.type === "post" || item.state !== "pending"
+    );
+  }
+
   if (filters.sort === "byDate") {
     return filteredItems.sort((a, b) => b.datetime - a.datetime);
   }
diff --git a/typings/cf2021.d.ts b/typings/cf2021.d.ts
index 63f15a564d6993b5dc6d2502a610016b285d4d7f..7c0d20197581b1952f9069d73ce8999558d62e59 100644
--- a/typings/cf2021.d.ts
+++ b/typings/cf2021.d.ts
@@ -124,6 +124,7 @@ declare namespace CF2021 {
     flags: "all" | "active" | "archived";
     sort: "byDate" | "byScore";
     type: "all" | "proposalsOnly" | "discussionOnly";
+    showPendingProposals: boolean;
   }
 
   export interface PostStorePayload {