diff --git a/.eslintrc.js b/.eslintrc.js
index 9653190ca8f28677b6bcc41aa57bdd1c1100f659..95078706ffa1d764424a75e46d9ac1da33bb259b 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -281,8 +281,8 @@ module.exports = {
         './packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx',
         './packages/desktop-client/src/components/budget/index.tsx',
         './packages/desktop-client/src/components/budget/MobileBudget.tsx',
-        './packages/desktop-client/src/components/budget/rollover/HoldTooltip.tsx',
-        './packages/desktop-client/src/components/budget/rollover/TransferTooltip.tsx',
+        './packages/desktop-client/src/components/budget/rollover/HoldMenu.tsx',
+        './packages/desktop-client/src/components/budget/rollover/TransferMenu.tsx',
         './packages/desktop-client/src/components/common/Menu.tsx',
         './packages/desktop-client/src/components/FinancesApp.tsx',
         './packages/desktop-client/src/components/GlobalKeys.ts',
diff --git a/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png b/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png
index 859d3bc11ea5dad29e10ac05b762216c12c1670b..965136b385cd1fdef63ad8e8013978c6732e8427 100644
Binary files a/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png and b/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-2-chromium-linux.png b/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-2-chromium-linux.png
index b75ff17d7272fcbd762fdf639f3a008e5914ecbd..0cad57c4c389d5903690580382edc679a972c818 100644
Binary files a/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-2-chromium-linux.png and b/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-2-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-3-chromium-linux.png b/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-3-chromium-linux.png
index 2911c4932381d33653345d60d2428cfbf38b68f3..d75b2db3e9e9e0f876fbfa97b11a3ff672307935 100644
Binary files a/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-3-chromium-linux.png and b/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-3-chromium-linux.png differ
diff --git a/packages/desktop-client/src/components/budget/BudgetTotals.tsx b/packages/desktop-client/src/components/budget/BudgetTotals.tsx
index 005e2afa939f1365135a987dc2bae76843c06cff..7126ff4d6add7223175da6c553410d3d4ef1e1ff 100644
--- a/packages/desktop-client/src/components/budget/BudgetTotals.tsx
+++ b/packages/desktop-client/src/components/budget/BudgetTotals.tsx
@@ -1,11 +1,11 @@
-import React, { type ComponentProps, memo, useState } from 'react';
+import React, { type ComponentProps, memo, useRef, useState } from 'react';
 
 import { SvgDotsHorizontalTriple } from '../../icons/v1';
 import { theme, styles } from '../../style';
 import { Button } from '../common/Button';
 import { Menu } from '../common/Menu';
+import { Popover } from '../common/Popover';
 import { View } from '../common/View';
-import { Tooltip } from '../tooltips';
 
 import { RenderMonths } from './RenderMonths';
 import { getScrollbarWidth } from './util';
@@ -24,6 +24,8 @@ export const BudgetTotals = memo(function BudgetTotals({
   collapseAllCategories,
 }: BudgetTotalsProps) {
   const [menuOpen, setMenuOpen] = useState(false);
+  const triggerRef = useRef(null);
+
   return (
     <View
       data-testid="budget-totals"
@@ -54,6 +56,7 @@ export const BudgetTotals = memo(function BudgetTotals({
       >
         <View style={{ flexGrow: '1' }}>Category</View>
         <Button
+          ref={triggerRef}
           type="bare"
           aria-label="Menu"
           onClick={() => {
@@ -66,44 +69,41 @@ export const BudgetTotals = memo(function BudgetTotals({
             height={15}
             style={{ color: theme.pageTextLight }}
           />
-          {menuOpen && (
-            <Tooltip
-              position="bottom-right"
-              width={200}
-              style={{ padding: 0 }}
-              onClose={() => {
-                setMenuOpen(false);
-              }}
-            >
-              <Menu
-                onMenuSelect={type => {
-                  if (type === 'toggle-visibility') {
-                    toggleHiddenCategories();
-                  } else if (type === 'expandAllCategories') {
-                    expandAllCategories();
-                  } else if (type === 'collapseAllCategories') {
-                    collapseAllCategories();
-                  }
-                  setMenuOpen(false);
-                }}
-                items={[
-                  {
-                    name: 'toggle-visibility',
-                    text: 'Toggle hidden categories',
-                  },
-                  {
-                    name: 'expandAllCategories',
-                    text: 'Expand all',
-                  },
-                  {
-                    name: 'collapseAllCategories',
-                    text: 'Collapse all',
-                  },
-                ]}
-              />
-            </Tooltip>
-          )}
         </Button>
+
+        <Popover
+          triggerRef={triggerRef}
+          isOpen={menuOpen}
+          onOpenChange={() => setMenuOpen(false)}
+          style={{ width: 200 }}
+        >
+          <Menu
+            onMenuSelect={type => {
+              if (type === 'toggle-visibility') {
+                toggleHiddenCategories();
+              } else if (type === 'expandAllCategories') {
+                expandAllCategories();
+              } else if (type === 'collapseAllCategories') {
+                collapseAllCategories();
+              }
+              setMenuOpen(false);
+            }}
+            items={[
+              {
+                name: 'toggle-visibility',
+                text: 'Toggle hidden categories',
+              },
+              {
+                name: 'expandAllCategories',
+                text: 'Expand all',
+              },
+              {
+                name: 'collapseAllCategories',
+                text: 'Collapse all',
+              },
+            ]}
+          />
+        </Popover>
       </View>
       <RenderMonths component={MonthComponent} />
     </View>
diff --git a/packages/desktop-client/src/components/budget/SidebarCategory.tsx b/packages/desktop-client/src/components/budget/SidebarCategory.tsx
index f62255cf91107c1d0b68135145ae92ca67bcb2d2..c8986725fe543079b45de359058c261c76787314 100644
--- a/packages/desktop-client/src/components/budget/SidebarCategory.tsx
+++ b/packages/desktop-client/src/components/budget/SidebarCategory.tsx
@@ -1,5 +1,5 @@
 // @ts-strict-ignore
-import React, { type CSSProperties, type Ref, useState } from 'react';
+import React, { type CSSProperties, type Ref, useRef, useState } from 'react';
 
 import {
   type CategoryGroupEntity,
@@ -10,10 +10,10 @@ import { SvgCheveronDown } from '../../icons/v1';
 import { theme } from '../../style';
 import { Button } from '../common/Button';
 import { Menu } from '../common/Menu';
+import { Popover } from '../common/Popover';
 import { View } from '../common/View';
 import { NotesButton } from '../NotesButton';
 import { InputCell } from '../table';
-import { Tooltip } from '../tooltips';
 
 type SidebarCategoryProps = {
   innerRef: Ref<HTMLDivElement>;
@@ -26,7 +26,7 @@ type SidebarCategoryProps = {
   borderColor?: string;
   isLast?: boolean;
   onEditName: (id: string) => void;
-  onSave: (group) => void;
+  onSave: (category: CategoryEntity) => void;
   onDelete: (id: string) => Promise<void>;
   onHideNewCategory?: () => void;
 };
@@ -47,6 +47,7 @@ export function SidebarCategory({
 }: SidebarCategoryProps) {
   const temporary = category.id === 'new';
   const [menuOpen, setMenuOpen] = useState(false);
+  const triggerRef = useRef(null);
 
   const displayed = (
     <View
@@ -69,7 +70,7 @@ export function SidebarCategory({
       >
         {category.name}
       </div>
-      <View style={{ flexShrink: 0, marginLeft: 5 }}>
+      <View style={{ flexShrink: 0, marginLeft: 5 }} ref={triggerRef}>
         <Button
           type="bare"
           className="hover-visible"
@@ -85,35 +86,35 @@ export function SidebarCategory({
             style={{ color: 'currentColor' }}
           />
         </Button>
-        {menuOpen && (
-          <Tooltip
-            position="bottom-left"
-            width={200}
-            style={{ padding: 0 }}
-            onClose={() => setMenuOpen(false)}
-          >
-            <Menu
-              onMenuSelect={type => {
-                if (type === 'rename') {
-                  onEditName(category.id);
-                } else if (type === 'delete') {
-                  onDelete(category.id);
-                } else if (type === 'toggle-visibility') {
-                  onSave({ ...category, hidden: !category.hidden });
-                }
-                setMenuOpen(false);
-              }}
-              items={[
-                !categoryGroup?.hidden && {
-                  name: 'toggle-visibility',
-                  text: category.hidden ? 'Show' : 'Hide',
-                },
-                { name: 'rename', text: 'Rename' },
-                { name: 'delete', text: 'Delete' },
-              ]}
-            />
-          </Tooltip>
-        )}
+
+        <Popover
+          triggerRef={triggerRef}
+          placement="bottom start"
+          isOpen={menuOpen}
+          onOpenChange={() => setMenuOpen(false)}
+          style={{ width: 200 }}
+        >
+          <Menu
+            onMenuSelect={type => {
+              if (type === 'rename') {
+                onEditName(category.id);
+              } else if (type === 'delete') {
+                onDelete(category.id);
+              } else if (type === 'toggle-visibility') {
+                onSave({ ...category, hidden: !category.hidden });
+              }
+              setMenuOpen(false);
+            }}
+            items={[
+              !categoryGroup?.hidden && {
+                name: 'toggle-visibility',
+                text: category.hidden ? 'Show' : 'Hide',
+              },
+              { name: 'rename', text: 'Rename' },
+              { name: 'delete', text: 'Delete' },
+            ]}
+          />
+        </Popover>
       </View>
       <View style={{ flex: 1 }} />
       <NotesButton
diff --git a/packages/desktop-client/src/components/budget/SidebarGroup.tsx b/packages/desktop-client/src/components/budget/SidebarGroup.tsx
index c762540579be6723437795435822c86acaae671e..0c9e3b4ec6329d3b4f80449120691c92dc89debf 100644
--- a/packages/desktop-client/src/components/budget/SidebarGroup.tsx
+++ b/packages/desktop-client/src/components/budget/SidebarGroup.tsx
@@ -1,5 +1,5 @@
 // @ts-strict-ignore
-import React, { type CSSProperties, useState } from 'react';
+import React, { type CSSProperties, useRef, useState } from 'react';
 import { type ConnectDragSource } from 'react-dnd';
 
 import { SvgExpandArrow } from '../../icons/v0';
@@ -7,11 +7,11 @@ import { SvgCheveronDown } from '../../icons/v1';
 import { theme } from '../../style';
 import { Button } from '../common/Button';
 import { Menu } from '../common/Menu';
+import { Popover } from '../common/Popover';
 import { Text } from '../common/Text';
 import { View } from '../common/View';
 import { NotesButton } from '../NotesButton';
 import { InputCell } from '../table';
-import { Tooltip } from '../tooltips';
 
 type SidebarGroupProps = {
   group: {
@@ -52,6 +52,7 @@ export function SidebarGroup({
 }: SidebarGroupProps) {
   const temporary = group.id === 'new';
   const [menuOpen, setMenuOpen] = useState(false);
+  const triggerRef = useRef(null);
 
   const displayed = (
     <View
@@ -91,7 +92,7 @@ export function SidebarGroup({
       </div>
       {!dragPreview && (
         <>
-          <View style={{ marginLeft: 5, flexShrink: 0 }}>
+          <View style={{ marginLeft: 5, flexShrink: 0 }} ref={triggerRef}>
             <Button
               type="bare"
               className="hover-visible"
@@ -103,38 +104,38 @@ export function SidebarGroup({
             >
               <SvgCheveronDown width={14} height={14} />
             </Button>
-            {menuOpen && (
-              <Tooltip
-                position="bottom-left"
-                width={200}
-                style={{ padding: 0 }}
-                onClose={() => setMenuOpen(false)}
-              >
-                <Menu
-                  onMenuSelect={type => {
-                    if (type === 'rename') {
-                      onEdit(group.id);
-                    } else if (type === 'add-category') {
-                      onShowNewCategory(group.id);
-                    } else if (type === 'delete') {
-                      onDelete(group.id);
-                    } else if (type === 'toggle-visibility') {
-                      onSave({ ...group, hidden: !group.hidden });
-                    }
-                    setMenuOpen(false);
-                  }}
-                  items={[
-                    { name: 'add-category', text: 'Add category' },
-                    !group.is_income && {
-                      name: 'toggle-visibility',
-                      text: group.hidden ? 'Show' : 'Hide',
-                    },
-                    { name: 'rename', text: 'Rename' },
-                    onDelete && { name: 'delete', text: 'Delete' },
-                  ]}
-                />
-              </Tooltip>
-            )}
+
+            <Popover
+              triggerRef={triggerRef}
+              placement="bottom start"
+              isOpen={menuOpen}
+              onOpenChange={() => setMenuOpen(false)}
+              style={{ width: 200 }}
+            >
+              <Menu
+                onMenuSelect={type => {
+                  if (type === 'rename') {
+                    onEdit(group.id);
+                  } else if (type === 'add-category') {
+                    onShowNewCategory(group.id);
+                  } else if (type === 'delete') {
+                    onDelete(group.id);
+                  } else if (type === 'toggle-visibility') {
+                    onSave({ ...group, hidden: !group.hidden });
+                  }
+                  setMenuOpen(false);
+                }}
+                items={[
+                  { name: 'add-category', text: 'Add category' },
+                  !group.is_income && {
+                    name: 'toggle-visibility',
+                    text: group.hidden ? 'Show' : 'Hide',
+                  },
+                  { name: 'rename', text: 'Rename' },
+                  onDelete && { name: 'delete', text: 'Delete' },
+                ]}
+              />
+            </Popover>
           </View>
           <View style={{ flex: 1 }} />
           <NotesButton
diff --git a/packages/desktop-client/src/components/budget/rollover/BalanceTooltip.tsx b/packages/desktop-client/src/components/budget/rollover/BalanceMovementMenu.tsx
similarity index 52%
rename from packages/desktop-client/src/components/budget/rollover/BalanceTooltip.tsx
rename to packages/desktop-client/src/components/budget/rollover/BalanceMovementMenu.tsx
index 1432556c096ce5f58dbc5ed931cb397345e2bf6e..0957b7bc827088147d488fa580fa37254fb796bb 100644
--- a/packages/desktop-client/src/components/budget/rollover/BalanceTooltip.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/BalanceMovementMenu.tsx
@@ -3,66 +3,49 @@ import React, { useState } from 'react';
 import { rolloverBudget } from 'loot-core/src/client/queries';
 
 import { useSheetValue } from '../../spreadsheet/useSheetValue';
-import { Tooltip } from '../../tooltips';
 
 import { BalanceMenu } from './BalanceMenu';
-import { CoverTooltip } from './CoverTooltip';
-import { TransferTooltip } from './TransferTooltip';
+import { CoverMenu } from './CoverMenu';
+import { TransferMenu } from './TransferMenu';
 
-type BalanceTooltipProps = {
+type BalanceMovementMenuProps = {
   categoryId: string;
-  tooltip: { close: () => void };
   month: string;
   onBudgetAction: (month: string, action: string, arg?: unknown) => void;
   onClose?: () => void;
 };
 
-export function BalanceTooltip({
+export function BalanceMovementMenu({
   categoryId,
-  tooltip,
   month,
   onBudgetAction,
-  onClose,
-  ...tooltipProps
-}: BalanceTooltipProps) {
+  onClose = () => {},
+}: BalanceMovementMenuProps) {
   const catBalance = useSheetValue(rolloverBudget.catBalance(categoryId));
   const [menu, setMenu] = useState('menu');
 
-  const _onClose = () => {
-    tooltip.close();
-    onClose?.();
-  };
-
   return (
     <>
       {menu === 'menu' && (
-        <Tooltip
-          position="bottom-right"
-          width={200}
-          style={{ padding: 0 }}
-          onClose={_onClose}
-          {...tooltipProps}
-        >
-          <BalanceMenu
-            categoryId={categoryId}
-            onCarryover={carryover => {
-              onBudgetAction(month, 'carryover', {
-                category: categoryId,
-                flag: carryover,
-              });
-              _onClose();
-            }}
-            onTransfer={() => setMenu('transfer')}
-            onCover={() => setMenu('cover')}
-          />
-        </Tooltip>
+        <BalanceMenu
+          categoryId={categoryId}
+          onCarryover={carryover => {
+            onBudgetAction(month, 'carryover', {
+              category: categoryId,
+              flag: carryover,
+            });
+            onClose();
+          }}
+          onTransfer={() => setMenu('transfer')}
+          onCover={() => setMenu('cover')}
+        />
       )}
 
       {menu === 'transfer' && (
-        <TransferTooltip
+        <TransferMenu
           initialAmount={catBalance}
           showToBeBudgeted={true}
-          onClose={_onClose}
+          onClose={onClose}
           onSubmit={(amount, toCategoryId) => {
             onBudgetAction(month, 'transfer-category', {
               amount,
@@ -74,8 +57,8 @@ export function BalanceTooltip({
       )}
 
       {menu === 'cover' && (
-        <CoverTooltip
-          onClose={_onClose}
+        <CoverMenu
+          onClose={onClose}
           onSubmit={fromCategoryId => {
             onBudgetAction(month, 'cover', {
               to: categoryId,
diff --git a/packages/desktop-client/src/components/budget/rollover/CoverTooltip.tsx b/packages/desktop-client/src/components/budget/rollover/CoverMenu.tsx
similarity index 71%
rename from packages/desktop-client/src/components/budget/rollover/CoverTooltip.tsx
rename to packages/desktop-client/src/components/budget/rollover/CoverMenu.tsx
index 60458e71e8ecfb033bab8f6b0bf8d60b0ca4b798..d321357adfdbbc95d16f6f5cf64f0a2322a2ca5c 100644
--- a/packages/desktop-client/src/components/budget/rollover/CoverTooltip.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/CoverMenu.tsx
@@ -1,46 +1,18 @@
-import React, { type ComponentProps, useState } from 'react';
+import React, { useState } from 'react';
 
 import { useCategories } from '../../../hooks/useCategories';
 import { CategoryAutocomplete } from '../../autocomplete/CategoryAutocomplete';
 import { Button } from '../../common/Button';
 import { InitialFocus } from '../../common/InitialFocus';
 import { View } from '../../common/View';
-import { Tooltip } from '../../tooltips';
 import { addToBeBudgetedGroup } from '../util';
 
-type CoverTooltipProps = {
-  tooltipProps?: ComponentProps<typeof Tooltip>;
+type CoverMenuProps = {
   onSubmit: (categoryId: string) => void;
   onClose: () => void;
 };
-export function CoverTooltip({
-  tooltipProps,
-  onSubmit,
-  onClose,
-}: CoverTooltipProps) {
-  const _onSubmit = (categoryId: string) => {
-    onSubmit?.(categoryId);
-    onClose?.();
-  };
 
-  return (
-    <Tooltip
-      position="bottom-right"
-      width={200}
-      style={{ padding: 10 }}
-      {...tooltipProps}
-      onClose={onClose}
-    >
-      <Cover onSubmit={_onSubmit} />
-    </Tooltip>
-  );
-}
-
-type CoverProps = {
-  onSubmit: (categoryId: string) => void;
-};
-
-function Cover({ onSubmit }: CoverProps) {
+export function CoverMenu({ onSubmit, onClose }: CoverMenuProps) {
   const { grouped: originalCategoryGroups } = useCategories();
   const categoryGroups = addToBeBudgetedGroup(
     originalCategoryGroups.filter(g => !g.is_income),
@@ -51,9 +23,10 @@ function Cover({ onSubmit }: CoverProps) {
     if (categoryId) {
       onSubmit(categoryId);
     }
+    onClose();
   }
   return (
-    <>
+    <View style={{ padding: 10 }}>
       <View style={{ marginBottom: 5 }}>Cover from category:</View>
 
       <InitialFocus>
@@ -94,6 +67,6 @@ function Cover({ onSubmit }: CoverProps) {
           Transfer
         </Button>
       </View>
-    </>
+    </View>
   );
 }
diff --git a/packages/desktop-client/src/components/budget/rollover/HoldTooltip.tsx b/packages/desktop-client/src/components/budget/rollover/HoldMenu.tsx
similarity index 80%
rename from packages/desktop-client/src/components/budget/rollover/HoldTooltip.tsx
rename to packages/desktop-client/src/components/budget/rollover/HoldMenu.tsx
index a2a4e69025e310ff3ab67abae933cbe46c99a1bb..c935e7f10ba1755e0f52c4296e84c98bfbe64518 100644
--- a/packages/desktop-client/src/components/budget/rollover/HoldTooltip.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/HoldMenu.tsx
@@ -3,7 +3,6 @@ import React, {
   useContext,
   useEffect,
   type ChangeEvent,
-  type ComponentPropsWithoutRef,
 } from 'react';
 
 import { useSpreadsheet } from 'loot-core/src/client/SpreadsheetProvider';
@@ -15,17 +14,12 @@ import { InitialFocus } from '../../common/InitialFocus';
 import { Input } from '../../common/Input';
 import { View } from '../../common/View';
 import { NamespaceContext } from '../../spreadsheet/NamespaceContext';
-import { Tooltip } from '../../tooltips';
 
-type HoldTooltipProps = ComponentPropsWithoutRef<typeof Tooltip> & {
+type HoldMenuProps = {
   onSubmit: (amount: number) => void;
+  onClose: () => void;
 };
-export function HoldTooltip({
-  onSubmit,
-  onClose,
-  position = 'bottom-right',
-  ...props
-}: HoldTooltipProps) {
+export function HoldMenu({ onSubmit, onClose }: HoldMenuProps) {
   const spreadsheet = useSpreadsheet();
   const sheetName = useContext(NamespaceContext);
 
@@ -47,18 +41,12 @@ export function HoldTooltip({
   }
 
   if (amount === null) {
-    // See `TransferTooltip` for more info about this
+    // See `TransferMenu` for more info about this
     return null;
   }
 
   return (
-    <Tooltip
-      position={position}
-      width={200}
-      style={{ padding: 10 }}
-      onClose={onClose}
-      {...props}
-    >
+    <View style={{ padding: 10 }}>
       <View style={{ marginBottom: 5 }}>Hold this amount:</View>
       <View>
         <InitialFocus>
@@ -89,6 +77,6 @@ export function HoldTooltip({
           Hold
         </Button>
       </View>
-    </Tooltip>
+    </View>
   );
 }
diff --git a/packages/desktop-client/src/components/budget/rollover/RolloverComponents.tsx b/packages/desktop-client/src/components/budget/rollover/RolloverComponents.tsx
index b1ba0ff719eb6072fcb3657e83a5787ff435ca79..492fb5b1c5a0880aa31a3703a1edb791174fde11 100644
--- a/packages/desktop-client/src/components/budget/rollover/RolloverComponents.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/RolloverComponents.tsx
@@ -1,5 +1,5 @@
 import type React from 'react';
-import { memo, useState } from 'react';
+import { memo, useRef, useState } from 'react';
 
 import { rolloverBudget } from 'loot-core/src/client/queries';
 import { evalArithmetic } from 'loot-core/src/shared/arithmetic';
@@ -8,16 +8,16 @@ import { integerToCurrency, amountToInteger } from 'loot-core/src/shared/util';
 import { SvgCheveronDown } from '../../../icons/v1';
 import { styles, theme, type CSSProperties } from '../../../style';
 import { Button } from '../../common/Button';
+import { Popover } from '../../common/Popover';
 import { Text } from '../../common/Text';
 import { View } from '../../common/View';
 import { CellValue } from '../../spreadsheet/CellValue';
 import { useFormat } from '../../spreadsheet/useFormat';
 import { Row, Field, SheetCell } from '../../table';
-import { Tooltip, useTooltip } from '../../tooltips';
 import { BalanceWithCarryover } from '../BalanceWithCarryover';
 import { makeAmountGrey } from '../util';
 
-import { BalanceTooltip } from './BalanceTooltip';
+import { BalanceMovementMenu } from './BalanceMovementMenu';
 import { BudgetMenu } from './BudgetMenu';
 
 const headerLabelStyle: CSSProperties = {
@@ -152,8 +152,10 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({
   onBudgetAction,
   onShowActivity,
 }: ExpenseCategoryMonthProps) {
-  const balanceTooltip = useTooltip();
-  const [menuOpen, setMenuOpen] = useState(false);
+  const budgetMenuTriggerRef = useRef(null);
+  const balanceMenuTriggerRef = useRef(null);
+  const [budgetMenuOpen, setBudgetMenuOpen] = useState(false);
+  const [balanceMenuOpen, setBalanceMenuOpen] = useState(false);
   const [hover, setHover] = useState(false);
 
   return (
@@ -180,7 +182,7 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({
           setHover(false);
         }}
       >
-        {!editing && (hover || menuOpen) ? (
+        {!editing && (hover || budgetMenuOpen) ? (
           <View
             style={{
               flexShrink: 1,
@@ -192,10 +194,11 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({
             }}
           >
             <Button
+              ref={budgetMenuTriggerRef}
               type="bare"
               onClick={e => {
                 e.stopPropagation();
-                setMenuOpen(true);
+                setBudgetMenuOpen(true);
               }}
               style={{
                 padding: 3,
@@ -205,47 +208,43 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({
                 width={14}
                 height={14}
                 className="hover-visible"
-                style={menuOpen ? { opacity: 1 } : {}}
+                style={budgetMenuOpen ? { opacity: 1 } : {}}
               />
             </Button>
-            {menuOpen && (
-              <Tooltip
-                position="bottom-left"
-                width={200}
-                style={{ padding: 0 }}
-                onClose={() => setMenuOpen(false)}
-              >
-                <BudgetMenu
-                  onCopyLastMonthAverage={() => {
-                    onBudgetAction?.(month, 'copy-single-last', {
-                      category: category.id,
-                    });
-                  }}
-                  onSetMonthsAverage={numberOfMonths => {
-                    if (
-                      numberOfMonths !== 3 &&
-                      numberOfMonths !== 6 &&
-                      numberOfMonths !== 12
-                    ) {
-                      return;
-                    }
 
-                    onBudgetAction?.(
-                      month,
-                      `set-single-${numberOfMonths}-avg`,
-                      {
-                        category: category.id,
-                      },
-                    );
-                  }}
-                  onApplyBudgetTemplate={() => {
-                    onBudgetAction?.(month, 'apply-single-category-template', {
-                      category: category.id,
-                    });
-                  }}
-                />
-              </Tooltip>
-            )}
+            <Popover
+              triggerRef={budgetMenuTriggerRef}
+              placement="bottom start"
+              isOpen={budgetMenuOpen}
+              onOpenChange={() => setBudgetMenuOpen(false)}
+              style={{ width: 200 }}
+            >
+              <BudgetMenu
+                onCopyLastMonthAverage={() => {
+                  onBudgetAction?.(month, 'copy-single-last', {
+                    category: category.id,
+                  });
+                }}
+                onSetMonthsAverage={numberOfMonths => {
+                  if (
+                    numberOfMonths !== 3 &&
+                    numberOfMonths !== 6 &&
+                    numberOfMonths !== 12
+                  ) {
+                    return;
+                  }
+
+                  onBudgetAction?.(month, `set-single-${numberOfMonths}-avg`, {
+                    category: category.id,
+                  });
+                }}
+                onApplyBudgetTemplate={() => {
+                  onBudgetAction?.(month, 'apply-single-category-template', {
+                    category: category.id,
+                  });
+                }}
+              />
+            </Popover>
           </View>
         ) : null}
         <SheetCell
@@ -315,7 +314,10 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({
         width="flex"
         style={{ paddingRight: styles.monthRightPadding, textAlign: 'right' }}
       >
-        <span {...balanceTooltip.getOpenEvents()}>
+        <span
+          ref={balanceMenuTriggerRef}
+          onClick={() => setBalanceMenuOpen(true)}
+        >
           <BalanceWithCarryover
             carryover={rolloverBudget.catCarryover(category.id)}
             balance={rolloverBudget.catBalance(category.id)}
@@ -323,14 +325,21 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({
             budgeted={rolloverBudget.catBudgeted(category.id)}
           />
         </span>
-        {balanceTooltip.isOpen && (
-          <BalanceTooltip
+
+        <Popover
+          triggerRef={balanceMenuTriggerRef}
+          placement="bottom end"
+          isOpen={balanceMenuOpen}
+          onOpenChange={() => setBalanceMenuOpen(false)}
+          style={{ width: 200 }}
+        >
+          <BalanceMovementMenu
             categoryId={category.id}
-            tooltip={balanceTooltip}
             month={month}
             onBudgetAction={onBudgetAction}
+            onClose={() => setBalanceMenuOpen(false)}
           />
-        )}
+        </Popover>
       </Field>
     </View>
   );
diff --git a/packages/desktop-client/src/components/budget/rollover/TransferTooltip.tsx b/packages/desktop-client/src/components/budget/rollover/TransferMenu.tsx
similarity index 71%
rename from packages/desktop-client/src/components/budget/rollover/TransferTooltip.tsx
rename to packages/desktop-client/src/components/budget/rollover/TransferMenu.tsx
index f23e53ca5f1eaf82bb0cee77d9396f80dcaffaf2..544504ab480b4366fa1d38468a13e4a41009be4a 100644
--- a/packages/desktop-client/src/components/budget/rollover/TransferTooltip.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/TransferMenu.tsx
@@ -1,5 +1,4 @@
-import type React from 'react';
-import { useState, type ComponentPropsWithoutRef } from 'react';
+import React, { useState } from 'react';
 
 import { evalArithmetic } from 'loot-core/src/shared/arithmetic';
 import { integerToCurrency, amountToInteger } from 'loot-core/src/shared/util';
@@ -10,52 +9,21 @@ import { Button } from '../../common/Button';
 import { InitialFocus } from '../../common/InitialFocus';
 import { Input } from '../../common/Input';
 import { View } from '../../common/View';
-import { Tooltip } from '../../tooltips';
 import { addToBeBudgetedGroup } from '../util';
 
-type TransferTooltipProps = ComponentPropsWithoutRef<typeof Tooltip> & {
+type TransferMenuProps = {
   initialAmount?: number;
   showToBeBudgeted?: boolean;
   onSubmit: (amount: number, categoryId: string) => void;
+  onClose: () => void;
 };
 
-export function TransferTooltip({
+export function TransferMenu({
   initialAmount = 0,
   showToBeBudgeted,
   onSubmit,
   onClose,
-  position = 'bottom-right',
-  ...props
-}: TransferTooltipProps) {
-  const _onSubmit = (amount: number, categoryId: string) => {
-    onSubmit?.(amount, categoryId);
-    onClose?.();
-  };
-
-  return (
-    <Tooltip
-      position={position}
-      width={200}
-      style={{ padding: 10 }}
-      onClose={onClose}
-      {...props}
-    >
-      <Transfer amount={initialAmount} showToBeBudgeted onSubmit={_onSubmit} />
-    </Tooltip>
-  );
-}
-
-type TransferProps = {
-  amount: number;
-  showToBeBudgeted: boolean;
-  onSubmit: (amount: number, categoryId: string) => void;
-};
-
-function Transfer({
-  amount: initialAmount,
-  showToBeBudgeted,
-  onSubmit,
-}: TransferProps) {
+}: TransferMenuProps) {
   const { grouped: originalCategoryGroups } = useCategories();
   let categoryGroups = originalCategoryGroups.filter(g => !g.is_income);
   if (showToBeBudgeted) {
@@ -71,10 +39,12 @@ function Transfer({
     if (parsedAmount && categoryId) {
       onSubmit?.(amountToInteger(parsedAmount), categoryId);
     }
+
+    onClose();
   };
 
   return (
-    <>
+    <View style={{ padding: 10 }}>
       <View style={{ marginBottom: 5 }}>Transfer this amount:</View>
       <View>
         <InitialFocus>
@@ -93,7 +63,8 @@ function Transfer({
         openOnFocus={true}
         onSelect={(id: string | undefined) => setCategoryId(id || null)}
         inputProps={{
-          onEnter: () => _onSubmit(amount, categoryId),
+          onEnter: event =>
+            !event.defaultPrevented && _onSubmit(amount, categoryId),
           placeholder: '(none)',
         }}
         showHiddenCategories={true}
@@ -117,6 +88,6 @@ function Transfer({
           Transfer
         </Button>
       </View>
-    </>
+    </View>
   );
 }
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
index a63e573fbde8e8e91cfc88a028c97fc629234f63..b1f65c7f9c8d32481a19978c60bc80d080ecc4c8 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
@@ -192,7 +192,6 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
             }}
           >
             <ToBudget
-              showTotalsTooltipOnHover={true}
               prevMonthName={prevMonthName}
               month={month}
               onBudgetAction={onBudgetAction}
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudget.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudget.tsx
index 5630ad92bfec8c4b9f7778793b43a4427858402d..8d5234b1c5f602b5c032ab893af695bffc1b449c 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudget.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudget.tsx
@@ -1,12 +1,13 @@
-import React, { useState, type ComponentPropsWithoutRef } from 'react';
+import React, { useRef, useState } from 'react';
 
 import { rolloverBudget } from 'loot-core/src/client/queries';
 
 import { type CSSProperties } from '../../../../style';
+import { Popover } from '../../../common/Popover';
+import { View } from '../../../common/View';
 import { useSheetValue } from '../../../spreadsheet/useSheetValue';
-import { Tooltip } from '../../../tooltips';
-import { HoldTooltip } from '../HoldTooltip';
-import { TransferTooltip } from '../TransferTooltip';
+import { HoldMenu } from '../HoldMenu';
+import { TransferMenu } from '../TransferMenu';
 
 import { ToBudgetAmount } from './ToBudgetAmount';
 import { ToBudgetMenu } from './ToBudgetMenu';
@@ -15,27 +16,18 @@ type ToBudgetProps = {
   month: string;
   onBudgetAction: (month: string, action: string, arg?: unknown) => void;
   prevMonthName: string;
-  showTotalsTooltipOnHover?: boolean;
   style?: CSSProperties;
   amountStyle?: CSSProperties;
-  menuTooltipProps?: ComponentPropsWithoutRef<typeof Tooltip>;
-  totalsTooltipProps?: ComponentPropsWithoutRef<typeof Tooltip>;
-  holdTooltipProps?: ComponentPropsWithoutRef<typeof HoldTooltip>;
-  transferTooltipProps?: ComponentPropsWithoutRef<typeof TransferTooltip>;
 };
 export function ToBudget({
   month,
   prevMonthName,
-  showTotalsTooltipOnHover,
   onBudgetAction,
   style,
   amountStyle,
-  menuTooltipProps,
-  totalsTooltipProps,
-  holdTooltipProps,
-  transferTooltipProps,
 }: ToBudgetProps) {
   const [menuOpen, setMenuOpen] = useState<string | null>(null);
+  const triggerRef = useRef(null);
   const sheetValue = useSheetValue({
     name: rolloverBudget.toBudget,
     value: 0,
@@ -44,22 +36,23 @@ export function ToBudget({
 
   return (
     <>
-      <ToBudgetAmount
-        onClick={() => setMenuOpen('actions')}
-        prevMonthName={prevMonthName}
-        showTotalsTooltipOnHover={showTotalsTooltipOnHover}
-        totalsTooltipProps={totalsTooltipProps}
-        style={style}
-        amountStyle={amountStyle}
-      />
-      {menuOpen === 'actions' && (
-        <Tooltip
-          position="bottom-center"
-          width={200}
-          style={{ padding: 0 }}
-          onClose={() => setMenuOpen(null)}
-          {...menuTooltipProps}
-        >
+      <View ref={triggerRef}>
+        <ToBudgetAmount
+          onClick={() => setMenuOpen('actions')}
+          prevMonthName={prevMonthName}
+          style={style}
+          amountStyle={amountStyle}
+        />
+      </View>
+
+      <Popover
+        triggerRef={triggerRef}
+        placement="bottom"
+        isOpen={!!menuOpen}
+        onOpenChange={() => setMenuOpen(null)}
+        style={{ width: 200 }}
+      >
+        {menuOpen === 'actions' && (
           <ToBudgetMenu
             onTransfer={() => setMenuOpen('transfer')}
             onHoldBuffer={() => setMenuOpen('buffer')}
@@ -68,30 +61,28 @@ export function ToBudget({
               setMenuOpen(null);
             }}
           />
-        </Tooltip>
-      )}
-      {menuOpen === 'buffer' && (
-        <HoldTooltip
-          onClose={() => setMenuOpen(null)}
-          onSubmit={amount => {
-            onBudgetAction(month, 'hold', { amount });
-          }}
-          {...holdTooltipProps}
-        />
-      )}
-      {menuOpen === 'transfer' && (
-        <TransferTooltip
-          initialAmount={availableValue}
-          onClose={() => setMenuOpen(null)}
-          onSubmit={(amount, category) => {
-            onBudgetAction(month, 'transfer-available', {
-              amount,
-              category,
-            });
-          }}
-          {...transferTooltipProps}
-        />
-      )}
+        )}
+        {menuOpen === 'buffer' && (
+          <HoldMenu
+            onClose={() => setMenuOpen(null)}
+            onSubmit={amount => {
+              onBudgetAction(month, 'hold', { amount });
+            }}
+          />
+        )}
+        {menuOpen === 'transfer' && (
+          <TransferMenu
+            initialAmount={availableValue}
+            onClose={() => setMenuOpen(null)}
+            onSubmit={(amount, category) => {
+              onBudgetAction(month, 'transfer-available', {
+                amount,
+                category,
+              });
+            }}
+          />
+        )}
+      </Popover>
     </>
   );
 }
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetAmount.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetAmount.tsx
index 4764903c74b7f230f4211ee94bc4177800e6a980..693fb3a57f5e3d6fc59b52ca2d65d51b20b50894 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetAmount.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetAmount.tsx
@@ -1,4 +1,4 @@
-import React, { type ComponentPropsWithoutRef } from 'react';
+import React from 'react';
 
 import { css } from 'glamor';
 
@@ -6,20 +6,17 @@ import { rolloverBudget } from 'loot-core/src/client/queries';
 
 import { theme, styles, type CSSProperties } from '../../../../style';
 import { Block } from '../../../common/Block';
-import { HoverTarget } from '../../../common/HoverTarget';
+import { Tooltip } from '../../../common/Tooltip';
 import { View } from '../../../common/View';
 import { PrivacyFilter } from '../../../PrivacyFilter';
 import { useFormat } from '../../../spreadsheet/useFormat';
 import { useSheetName } from '../../../spreadsheet/useSheetName';
 import { useSheetValue } from '../../../spreadsheet/useSheetValue';
-import { Tooltip } from '../../../tooltips';
 
 import { TotalsList } from './TotalsList';
 
 type ToBudgetAmountProps = {
   prevMonthName: string;
-  showTotalsTooltipOnHover?: boolean;
-  totalsTooltipProps?: ComponentPropsWithoutRef<typeof Tooltip>;
   style?: CSSProperties;
   amountStyle?: CSSProperties;
   onClick: () => void;
@@ -27,8 +24,6 @@ type ToBudgetAmountProps = {
 
 export function ToBudgetAmount({
   prevMonthName,
-  showTotalsTooltipOnHover,
-  totalsTooltipProps,
   style,
   amountStyle,
   onClick,
@@ -47,18 +42,17 @@ export function ToBudgetAmount({
     <View style={{ alignItems: 'center', ...style }}>
       <Block>{isNegative ? 'Overbudgeted:' : 'To Budget:'}</Block>
       <View>
-        <HoverTarget
-          disabled={!showTotalsTooltipOnHover}
-          renderContent={() => (
-            <Tooltip position="bottom-center" {...totalsTooltipProps}>
-              <TotalsList
-                prevMonthName={prevMonthName}
-                style={{
-                  padding: 7,
-                }}
-              />
-            </Tooltip>
-          )}
+        <Tooltip
+          content={
+            <TotalsList
+              prevMonthName={prevMonthName}
+              style={{
+                padding: 7,
+              }}
+            />
+          }
+          placement="bottom"
+          triggerProps={{ delay: 0 }}
         >
           <PrivacyFilter blurIntensity={7}>
             <Block
@@ -85,7 +79,7 @@ export function ToBudgetAmount({
               {format(num, 'financial')}
             </Block>
           </PrivacyFilter>
-        </HoverTarget>
+        </Tooltip>
       </View>
     </View>
   );
diff --git a/packages/desktop-client/src/components/common/Menu.tsx b/packages/desktop-client/src/components/common/Menu.tsx
index 105f703aefdb59c162e95f900ff5a7b2120d12c9..709c7295bdd13c010182af4f8fe238dc03ae1c7e 100644
--- a/packages/desktop-client/src/components/common/Menu.tsx
+++ b/packages/desktop-client/src/components/common/Menu.tsx
@@ -167,11 +167,13 @@ export function Menu<T extends MenuItem>({
             }}
             onPointerEnter={() => setHoveredIndex(idx)}
             onPointerLeave={() => setHoveredIndex(null)}
-            onClick={() =>
-              !item.disabled &&
-              item.toggle === undefined &&
-              onMenuSelect?.(item.name)
-            }
+            onClick={e => {
+              e.stopPropagation();
+
+              if (!item.disabled && item.toggle === undefined) {
+                onMenuSelect?.(item.name);
+              }
+            }}
           >
             {/* Force it to line up evenly */}
             {item.toggle === undefined ? (
diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx
index 8df4a8c76df7f6c66467fd4d1d892eb24b220c8e..1a2f3b06c1d4eb9cef37f7776a4693e8c0bbf0c2 100644
--- a/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx
+++ b/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx
@@ -506,7 +506,7 @@ describe('Transactions', () => {
     // The category field should still be editing
     expectToBeEditingField(container, 'category', 2);
     // No dropdown should be open
-    expect(container.querySelector('[data-testid="autocomplete"]')).toBe(null);
+    expect(screen.queryByTestId('autocomplete')).toBe(null);
 
     // Pressing enter should now move down
     await userEvent.type(input, '[Enter]');
diff --git a/upcoming-release-notes/2724.md b/upcoming-release-notes/2724.md
new file mode 100644
index 0000000000000000000000000000000000000000..8c6ed88381b89c15c217bd2e245d7f329eccec7b
--- /dev/null
+++ b/upcoming-release-notes/2724.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [MatissJanis]
+---
+
+Migrating native `Tooltip` component to react-aria Tooltip/Popover (vol.4)