diff --git a/app/Resources/js/modules/Dropdown.ts b/app/Resources/js/modules/Dropdown.ts
index c896ff14e5153342a1444f65c0429613dcaef98e..06cfb9a531cdfe3e5c4a96de71583258066e0d73 100644
--- a/app/Resources/js/modules/Dropdown.ts
+++ b/app/Resources/js/modules/Dropdown.ts
@@ -1,4 +1,10 @@
-import { createPopper, Instance, Placement } from "@popperjs/core";
+import {
+  computePosition,
+  flip,
+  offset,
+  Placement,
+  shift,
+} from "@floating-ui/dom";
 
 const Dropdown = (): void => {
   const dropdownButtons: NodeListOf<HTMLButtonElement> =
@@ -16,46 +22,46 @@ const Dropdown = (): void => {
         // place the menu at then end of the body to prevent any overflow cuts
         document.body.appendChild(menu);
 
-        let popperInstance: Instance | null = null;
-
-        const create = () => {
+        const update = () => {
           const offsetX = menu.dataset.dropdownOffsetX
             ? parseInt(menu.dataset.dropdownOffsetX)
             : 0;
           const offsetY = menu.dataset.dropdownOffsetY
             ? parseInt(menu.dataset.dropdownOffsetY)
             : 0;
-          popperInstance = createPopper(button, menu, {
+          computePosition(button, menu, {
             placement: menu.dataset.dropdownPlacement as Placement,
-            modifiers: [
-              {
-                name: "offset",
-                options: {
-                  offset: [offsetX, offsetY],
-                },
-              },
+            middleware: [
+              offset({ mainAxis: offsetY, crossAxis: offsetX }),
+              flip(),
+              shift(),
             ],
+          }).then(({ x, y }) => {
+            Object.assign(menu.style, {
+              left: `${x}px`,
+              top: `${y}px`,
+            });
           });
         };
 
-        const destroy = () => {
-          if (popperInstance) {
-            popperInstance.destroy();
-            popperInstance = null;
-          }
+        const showMenu = () => {
+          menu.setAttribute("data-show", "");
+          button.setAttribute("aria-expanded", "true");
+          update();
+        };
+
+        const hideMenu = () => {
+          menu.removeAttribute("data-show");
+          button.setAttribute("aria-expanded", "false");
         };
 
         const dropdownToggle = () => {
           const isExpanded = menu.hasAttribute("data-show");
 
           if (isExpanded) {
-            menu.removeAttribute("data-show");
-            button.setAttribute("aria-expanded", "false");
-            destroy();
+            hideMenu();
           } else {
-            menu.setAttribute("data-show", "");
-            button.setAttribute("aria-expanded", "true");
-            create();
+            showMenu();
           }
         };
 
diff --git a/app/Resources/js/modules/Tooltip.ts b/app/Resources/js/modules/Tooltip.ts
index 47065dec5324f95139bbc286b80e54e46abfb48a..0d0d2733e7120aa04a5d6acc11e56da0cc7acf3b 100644
--- a/app/Resources/js/modules/Tooltip.ts
+++ b/app/Resources/js/modules/Tooltip.ts
@@ -1,4 +1,12 @@
-import { createPopper, Placement } from "@popperjs/core";
+import { Coords } from "@floating-ui/core";
+import {
+  arrow,
+  computePosition,
+  flip,
+  offset,
+  Placement,
+  shift,
+} from "@floating-ui/dom";
 
 const Tooltip = (): void => {
   const tooltipContainers: NodeListOf<HTMLElement> =
@@ -12,30 +20,60 @@ const Tooltip = (): void => {
     tooltip.setAttribute("id", "tooltip" + i);
     tooltip.setAttribute(
       "class",
-      "px-2 py-1 text-sm bg-gray-900 text-white rounded max-w-xs z-50"
+      "absolute px-2 py-1 text-sm bg-gray-900 text-white rounded max-w-xs z-50"
     );
     tooltip.innerHTML = tooltipContent;
+    const arrowElement = document.createElement("div");
+    arrowElement.setAttribute(
+      "class",
+      "absolute bg-gray-900 w-2 h-2 rotate-45"
+    );
+    arrowElement.setAttribute("id", "arrow" + i);
+    tooltip.appendChild(arrowElement);
 
-    const popper = createPopper(tooltipReference, tooltip, {
-      placement: tooltipReference.dataset.tooltip as Placement,
-      modifiers: [
-        {
-          name: "offset",
-          options: {
-            offset: [0, 8],
-          },
-        },
-      ],
-    });
+    const update = () => {
+      computePosition(tooltipReference, tooltip, {
+        placement: tooltipReference.dataset.tooltip as Placement,
+        middleware: [
+          flip(),
+          shift(),
+          offset(8),
+          arrow({ element: arrowElement }),
+        ],
+      }).then(({ x, y, placement, middlewareData }) => {
+        Object.assign(tooltip.style, {
+          left: `${x}px`,
+          top: `${y}px`,
+        });
+
+        // Accessing the data
+        const { x: arrowX, y: arrowY } = middlewareData.arrow as Coords;
+
+        const staticSide = {
+          top: "bottom",
+          right: "left",
+          bottom: "top",
+          left: "right",
+        }[placement.split("-")[0]];
+
+        Object.assign(arrowElement.style, {
+          left: arrowX != null ? `${arrowX}px` : "",
+          top: arrowY != null ? `${arrowY}px` : "",
+          right: "",
+          bottom: "",
+          [staticSide as string]: "-4px",
+        });
+      });
+    };
 
-    const show = () => {
+    const showTooltip = () => {
       tooltipReference.removeAttribute("title");
       tooltipReference.setAttribute("aria-describedby", "tooltip" + i);
       document.body.appendChild(tooltip);
-      popper.update();
+      update();
     };
 
-    const hide = () => {
+    const hideTooltip = () => {
       const element = document.getElementById("tooltip" + i);
       tooltipReference.removeAttribute("aria-describedby");
       tooltipReference.setAttribute("title", tooltipContent);
@@ -48,11 +86,11 @@ const Tooltip = (): void => {
     const hideEvents = ["mouseleave", "blur"];
 
     showEvents.forEach((event) => {
-      tooltipReference.addEventListener(event, show);
+      tooltipReference.addEventListener(event, showTooltip);
     });
 
     hideEvents.forEach((event) => {
-      tooltipReference.addEventListener(event, hide);
+      tooltipReference.addEventListener(event, hideTooltip);
     });
   }
 };
diff --git a/app/Resources/styles/dropdown.css b/app/Resources/styles/dropdown.css
index bf3e2ed00fc9033c6582a57ff342fd2641117626..850f8d35aae5e3121109528c06af14d65639d523 100644
--- a/app/Resources/styles/dropdown.css
+++ b/app/Resources/styles/dropdown.css
@@ -1,8 +1,8 @@
 @layer base {
   [data-dropdown="menu"] {
-    @apply z-50;
+    @apply absolute z-50;
   }
   [data-dropdown="menu"]:not([data-show]) {
-    @apply absolute top-0 left-0 invisible pointer-events-none;
+    @apply hidden;
   }
 }
diff --git a/package-lock.json b/package-lock.json
index aebd3b99526633b8b04ddc7564684df2bb2b59f7..7fa81b3761c77459f3ce12407921381e838a1b6e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,11 +16,11 @@
         "@codemirror/lang-xml": "^0.19.2",
         "@codemirror/state": "^0.19.6",
         "@codemirror/view": "^0.19.32",
+        "@floating-ui/dom": "^0.1.10",
         "@github/clipboard-copy-element": "^1.1.2",
         "@github/hotkey": "^1.6.1",
         "@github/markdown-toolbar-element": "^2.1.0",
         "@github/time-elements": "^3.1.2",
-        "@popperjs/core": "^2.11.0",
         "@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
         "@vime/core": "^5.3.0",
         "choices.js": "^9.0.1",
@@ -2355,6 +2355,19 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/@floating-ui/core": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.3.1.tgz",
+      "integrity": "sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g=="
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "0.1.10",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.1.10.tgz",
+      "integrity": "sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==",
+      "dependencies": {
+        "@floating-ui/core": "^0.3.0"
+      }
+    },
     "node_modules/@foliojs-fork/fontkit": {
       "version": "1.9.1",
       "license": "MIT",
@@ -2606,14 +2619,6 @@
         "@octokit/openapi-types": "^11.2.0"
       }
     },
-    "node_modules/@popperjs/core": {
-      "version": "2.11.0",
-      "license": "MIT",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/popperjs"
-      }
-    },
     "node_modules/@rollup/plugin-babel": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz",
@@ -18285,6 +18290,19 @@
         }
       }
     },
+    "@floating-ui/core": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.3.1.tgz",
+      "integrity": "sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g=="
+    },
+    "@floating-ui/dom": {
+      "version": "0.1.10",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.1.10.tgz",
+      "integrity": "sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==",
+      "requires": {
+        "@floating-ui/core": "^0.3.0"
+      }
+    },
     "@foliojs-fork/fontkit": {
       "version": "1.9.1",
       "requires": {
@@ -18491,9 +18509,6 @@
         "@octokit/openapi-types": "^11.2.0"
       }
     },
-    "@popperjs/core": {
-      "version": "2.11.0"
-    },
     "@rollup/plugin-babel": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz",
diff --git a/package.json b/package.json
index d619d3f90df19f9b1256f83d59cff47d871d350b..18c42eb02c657e1311fa034beebd14af5c177779 100644
--- a/package.json
+++ b/package.json
@@ -34,11 +34,11 @@
     "@codemirror/lang-xml": "^0.19.2",
     "@codemirror/state": "^0.19.6",
     "@codemirror/view": "^0.19.32",
+    "@floating-ui/dom": "^0.1.10",
     "@github/clipboard-copy-element": "^1.1.2",
     "@github/hotkey": "^1.6.1",
     "@github/markdown-toolbar-element": "^2.1.0",
     "@github/time-elements": "^3.1.2",
-    "@popperjs/core": "^2.11.0",
     "@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
     "@vime/core": "^5.3.0",
     "choices.js": "^9.0.1",