diff --git a/src/components/common/messaging/attachments/Attachment.module.scss b/src/components/common/messaging/attachments/Attachment.module.scss
index b3253ae31cd10ea94a234cc132131078f7ebe3b0..b7bf8c32051a2ab46394a09b6fc8e249a3bc7e8b 100644
--- a/src/components/common/messaging/attachments/Attachment.module.scss
+++ b/src/components/common/messaging/attachments/Attachment.module.scss
@@ -4,7 +4,7 @@
     grid-auto-flow: row dense;
     
     width: max-content;
-    
+
     border-radius: 6px;
     margin: .125rem 0 .125rem;
     
@@ -31,7 +31,7 @@
         }
     }
 
-    &.video {        
+    &.video {
         .actions {
             padding: 10px 12px;
             border-radius: 6px 6px 0 0;
diff --git a/src/components/markdown/Renderer.tsx b/src/components/markdown/Renderer.tsx
index b501a6848173ac726934683d0ddeaed74239656a..1b531460ac47215118eb53a2b3c3991e5578c8f7 100644
--- a/src/components/markdown/Renderer.tsx
+++ b/src/components/markdown/Renderer.tsx
@@ -13,7 +13,7 @@ import "prismjs/themes/prism-tomorrow.css";
 import { RE_MENTIONS } from "revolt.js";
 
 import styles from "./Markdown.module.scss";
-import { useContext } from "preact/hooks";
+import { useCallback, useContext, useRef } from "preact/hooks";
 
 import { internalEmit } from "../../lib/eventEmitter";
 
@@ -83,64 +83,6 @@ declare global {
     }
 }
 
-// Handler for internal links, pushes events to React using magic.
-if (typeof window !== "undefined") {
-    window.internalHandleURL = function (element: HTMLAnchorElement) {
-        const url = new URL(element.href, location.href);
-        const pathname = url.pathname;
-
-        if (pathname.startsWith("/@")) {
-            internalEmit("Intermediate", "openProfile", pathname.substr(2));
-        } else {
-            internalEmit("Intermediate", "navigate", pathname);
-        }
-    };
-}
-
-md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
-    let internal;
-    const hIndex = tokens[idx].attrIndex("href");
-    if (hIndex >= 0) {
-        try {
-            // For internal links, we should use our own handler to use react-router history.
-            // @ts-ignore
-            const href = tokens[idx].attrs[hIndex][1];
-            const url = new URL(href, location.href);
-
-            if (url.hostname === location.hostname) {
-                internal = true;
-                // I'm sorry.
-                tokens[idx].attrPush([
-                    "onclick",
-                    "internalHandleURL(this); return false",
-                ]);
-
-                if (url.pathname.startsWith("/@")) {
-                    tokens[idx].attrPush(["data-type", "mention"]);
-                }
-            }
-        } catch (err) {
-            // Ignore the error, treat as normal link.
-        }
-    }
-
-    if (!internal) {
-        // Add target=_blank for external links.
-        const aIndex = tokens[idx].attrIndex("target");
-
-        if (aIndex < 0) {
-            tokens[idx].attrPush(["target", "_blank"]);
-        } else {
-            try {
-                // @ts-ignore
-                tokens[idx].attrs[aIndex][1] = "_blank";
-            } catch (_) {}
-        }
-    }
-
-    return defaultRender(tokens, idx, options, env, self);
-};
-
 md.renderer.rules.emoji = function (token, idx) {
     return generateEmoji(token[idx].content);
 };
@@ -172,21 +114,74 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
         ? false
         : content.replace(RE_TWEMOJI, "").trim().length === 0;
 
+    const toggle = useCallback((ev: MouseEvent) => {
+        if (ev.currentTarget) {
+            let element = ev.currentTarget as HTMLDivElement;
+            if (element.classList.contains("spoiler")) {
+                element.classList.add("shown");
+            }
+        }
+    }, []);
+
+    const handleLink = useCallback((ev: MouseEvent) => {
+        ev.preventDefault();
+        if (ev.currentTarget) {
+            const element = ev.currentTarget as HTMLAnchorElement;
+            const url = new URL(element.href, location.href);
+            const pathname = url.pathname;
+
+            if (pathname.startsWith("/@")) {
+                internalEmit("Intermediate", "openProfile", pathname.substr(2));
+            } else {
+                internalEmit("Intermediate", "navigate", pathname);
+            }
+        }
+    }, []);
+
     return (
         <span
+            ref={el => {
+                if (el) {
+                    (el.querySelectorAll<HTMLDivElement>('.spoiler'))
+                        .forEach(element => {
+                            element.removeEventListener('click', toggle);
+                            element.addEventListener('click', toggle);
+                        });
+
+                    (el.querySelectorAll<HTMLAnchorElement>('a'))
+                        .forEach(element => {
+                            element.removeEventListener('click', handleLink);
+                            element.removeAttribute('data-type');
+                            element.removeAttribute('target');
+
+                            let internal;
+                            const href = element.href;
+                            if (href) {
+                                try {
+                                    const url = new URL(href, location.href);
+
+                                    if (url.hostname === location.hostname) {
+                                        internal = true;
+                                        element.addEventListener('click', handleLink);
+
+                                        if (url.pathname.startsWith('/@')) {
+                                            element.setAttribute('data-type', 'mention');
+                                        }
+                                    }
+                                } catch (err) {}
+                            }
+
+                            if (!internal) {
+                                element.setAttribute('target', '_blank');
+                            }
+                        });
+                }
+            }}
             className={styles.markdown}
             dangerouslySetInnerHTML={{
                 __html: md.render(newContent),
             }}
             data-large-emojis={useLargeEmojis}
-            onClick={(ev) => {
-                if (ev.target) {
-                    let element = ev.currentTarget;
-                    if (element.classList.contains("spoiler")) {
-                        element.classList.add("shown");
-                    }
-                }
-            }}
         />
     );
 }