diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-1-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-1-chromium-linux.png
index 66afa1a7866e980ade58f21f743bc12fa116eb61..6ca4a16dd3ddfdcdc661b5c236dbeb3228d210ca 100644
Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-1-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-1-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-2-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-2-chromium-linux.png
index 25eeeab52be1ef25e9626a989347c9e571371981..f52c2aec886feb2cba0de7bd923258c6693fe9a5 100644
Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-2-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-2-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-3-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-3-chromium-linux.png
index 46bf1b79121d31376fe0539a4e2e25801afbf614..b5934abb60d91677a97bc5bbd86cc7b509c97706 100644
Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-3-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-3-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-4-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-4-chromium-linux.png
index 3de1d448773b8cd5c37165660a859bbfe74783a9..2f8703bb8a4f47f6b45d635ed0093d7f04de3db5 100644
Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-4-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-4-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png
index 90efef73ea04b2aba2e2b4e25423809be6b80284..c8f465f9d28a425c75f19d366905ad921c390f4b 100644
Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-2-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-2-chromium-linux.png
index ae75ed2b3f1318cee0cd58dd7da4078db5f370e5..5540f29045f94c988a22ca8ca947490a21c14087 100644
Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-2-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-2-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-opens-the-accounts-page-and-asserts-on-balances-1-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-opens-the-accounts-page-and-asserts-on-balances-1-chromium-linux.png
index 43a9bdd4c2b0eb842d475b8fd95a07d507188b4f..0019449738afb4e2e00ebf52867e24174d1af811 100644
Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-opens-the-accounts-page-and-asserts-on-balances-1-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-opens-the-accounts-page-and-asserts-on-balances-1-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-opens-the-accounts-page-and-asserts-on-balances-2-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-opens-the-accounts-page-and-asserts-on-balances-2-chromium-linux.png
index de102f9e230f67f796662a43533d9fa8af136dd8..0cef62b3eda58234da6c26e3da4d5dd27a7a72b8 100644
Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-opens-the-accounts-page-and-asserts-on-balances-2-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-opens-the-accounts-page-and-asserts-on-balances-2-chromium-linux.png differ
diff --git a/packages/desktop-client/e2e/page-models/mobile-navigation.js b/packages/desktop-client/e2e/page-models/mobile-navigation.js
index eeabd4b4c0dae071b6445c893f201b860662664c..ebda4cbb777da27e3a7df0311821451c98b36c81 100644
--- a/packages/desktop-client/e2e/page-models/mobile-navigation.js
+++ b/packages/desktop-client/e2e/page-models/mobile-navigation.js
@@ -30,9 +30,17 @@ export class MobileNavigation {
   }
 
   async goToSettingsPage() {
+    await this.dragNavbarUp();
+
     const link = this.page.getByRole('link', { name: 'Settings' });
     await link.click();
 
     return new SettingsPage(this.page);
   }
+
+  async dragNavbarUp() {
+    await this.page
+      .getByRole('navigation')
+      .dragTo(this.page.getByTestId('budget-table'));
+  }
 }
diff --git a/packages/desktop-client/package.json b/packages/desktop-client/package.json
index 921766ab9e23c2e1c86f34d798992f9db504b7ce..7d242da4567472964489b58b016f171f30fb77a6 100644
--- a/packages/desktop-client/package.json
+++ b/packages/desktop-client/package.json
@@ -28,6 +28,7 @@
     "@types/react-router-dom": "^5.3.3",
     "@types/uuid": "^9.0.2",
     "@types/webpack-bundle-analyzer": "^4.6.0",
+    "@use-gesture/react": "^10.3.0",
     "chokidar": "^3.5.3",
     "cross-env": "^7.0.3",
     "date-fns": "^2.29.3",
diff --git a/packages/desktop-client/src/components/ScrollProvider.tsx b/packages/desktop-client/src/components/ScrollProvider.tsx
index 06e59fb60e168f4d6b20a61f2472e79a451e4b1b..45c39e0ac8e08efe8d3d26850798d8995b968a2a 100644
--- a/packages/desktop-client/src/components/ScrollProvider.tsx
+++ b/packages/desktop-client/src/components/ScrollProvider.tsx
@@ -29,7 +29,7 @@ export default function ScrollProvider({ children }: ScrollProviderProps) {
       setIsBottomReached(
         e.target?.scrollHeight - e.target?.scrollTop <= e.target?.clientHeight,
       );
-    }, 20);
+    }, 10);
 
     window.addEventListener('scroll', listenToScroll, {
       capture: true,
diff --git a/packages/desktop-client/src/components/mobile/MobileNavTabs.tsx b/packages/desktop-client/src/components/mobile/MobileNavTabs.tsx
index afa3c89b73ac4aaa709152b1c6e3043c19f299a4..454351e11c3c863d44d374443e955e64f95849b9 100644
--- a/packages/desktop-client/src/components/mobile/MobileNavTabs.tsx
+++ b/packages/desktop-client/src/components/mobile/MobileNavTabs.tsx
@@ -1,53 +1,200 @@
-import React, { type ComponentType, useMemo } from 'react';
+import React, { type ComponentType, useEffect } from 'react';
 import { NavLink } from 'react-router-dom';
+import { useSpring, animated, config } from 'react-spring';
+
+import { useDrag } from '@use-gesture/react';
 
 import usePrevious from '../../hooks/usePrevious';
 import Add from '../../icons/v1/Add';
 import Cog from '../../icons/v1/Cog';
 import PiggyBank from '../../icons/v1/PiggyBank';
+import StoreFront from '../../icons/v1/StoreFront';
+import Tuning from '../../icons/v1/Tuning';
 import Wallet from '../../icons/v1/Wallet';
+import Calendar from '../../icons/v2/Calendar';
 import { useResponsive } from '../../ResponsiveProvider';
-import { theme, styles } from '../../style';
+import { theme, styles, type CSSProperties } from '../../style';
+import View from '../common/View';
 import { useScroll } from '../ScrollProvider';
 
-const height = 70;
+const ROW_HEIGHT = 70;
+const COLUMN_COUNT = 3;
 
 export default function MobileNavTabs() {
   const { isNarrowWidth } = useResponsive();
-  const { scrollY, isBottomReached } = useScroll();
+  const { scrollY } = useScroll();
+
+  const navTabStyle = {
+    flex: `1 1 ${100 / COLUMN_COUNT}%`,
+    height: ROW_HEIGHT,
+    padding: 10,
+  };
+
+  const navTabs = [
+    {
+      name: 'Budget',
+      path: '/budget',
+      style: navTabStyle,
+      icon: Wallet,
+    },
+    {
+      name: 'Transaction',
+      path: '/transactions/new',
+      style: navTabStyle,
+      icon: Add,
+    },
+    {
+      name: 'Accounts',
+      path: '/accounts',
+      style: navTabStyle,
+      icon: PiggyBank,
+    },
+    {
+      name: 'Schedules (Soon)',
+      path: '/schedules/soon',
+      style: navTabStyle,
+      icon: Calendar,
+    },
+    {
+      name: 'Payees (Soon)',
+      path: '/payees/soon',
+      style: navTabStyle,
+      icon: StoreFront,
+    },
+    {
+      name: 'Rules (Soon)',
+      path: '/rules/soon',
+      style: navTabStyle,
+      icon: Tuning,
+    },
+    {
+      name: 'Settings',
+      path: '/settings',
+      style: navTabStyle,
+      icon: Cog,
+    },
+  ].map(tab => <NavTab key={tab.path} {...tab} />);
+
+  const bufferTabsCount = COLUMN_COUNT - (navTabs.length % COLUMN_COUNT);
+  const bufferTabs = Array.from({ length: bufferTabsCount }).map((_, idx) => (
+    <div key={idx} style={navTabStyle} />
+  ));
+
+  const totalHeight = ROW_HEIGHT * COLUMN_COUNT;
+  const openY = 0;
+  const closeY = totalHeight - ROW_HEIGHT;
+  const hiddenY = totalHeight;
+
+  const [{ y }, api] = useSpring(() => ({ y: totalHeight }));
+
+  const open = ({ canceled }) => {
+    // when cancel is true, it means that the user passed the upwards threshold
+    // so we change the spring config to create a nice wobbly effect
+    api.start({
+      y: openY,
+      immediate: false,
+      config: canceled ? config.wobbly : config.stiff,
+    });
+  };
+
+  const close = (velocity = 0) => {
+    api.start({
+      y: closeY,
+      immediate: false,
+      config: { ...config.stiff, velocity },
+    });
+  };
+
+  const hide = (velocity = 0) => {
+    api.start({
+      y: hiddenY,
+      immediate: false,
+      config: { ...config.stiff, velocity },
+    });
+  };
+
   const previousScrollY = usePrevious(scrollY);
 
-  const isVisible = useMemo(
-    () =>
-      previousScrollY === undefined ||
-      (!isBottomReached && previousScrollY > scrollY) ||
-      previousScrollY < 0,
-    [scrollY],
+  useEffect(() => {
+    if (
+      scrollY &&
+      previousScrollY &&
+      scrollY > previousScrollY &&
+      previousScrollY !== 0
+    ) {
+      hide();
+    } else {
+      close();
+    }
+  }, [scrollY]);
+
+  const bind = useDrag(
+    ({
+      last,
+      velocity: [, vy],
+      direction: [, dy],
+      offset: [, oy],
+      cancel,
+      canceled,
+    }) => {
+      // if the user drags up passed a threshold, then we cancel
+      // the drag so that the sheet resets to its open position
+      if (oy < 0) {
+        cancel();
+      }
+
+      // when the user releases the sheet, we check whether it passed
+      // the threshold for it to close, or if we reset it to its open position
+      if (last) {
+        if (oy > ROW_HEIGHT * 0.5 || (vy > 0.5 && dy > 0)) {
+          close(vy);
+        } else {
+          open({ canceled });
+        }
+      } else {
+        // when the user keeps dragging, we just move the sheet according to
+        // the cursor position
+        api.start({ y: oy, immediate: true });
+      }
+    },
+    {
+      from: () => [0, y.get()],
+      filterTaps: true,
+      bounds: { top: -totalHeight, bottom: totalHeight - ROW_HEIGHT },
+      axis: 'y',
+      rubberband: true,
+    },
   );
 
   return (
-    <div
+    <animated.div
+      role="navigation"
+      {...bind()}
       style={{
+        y,
+        touchAction: 'pan-x',
         backgroundColor: theme.mobileNavBackground,
         borderTop: `1px solid ${theme.menuBorder}`,
         ...styles.shadow,
-        display: isNarrowWidth ? 'flex' : 'none',
-        height,
-        justifyContent: 'space-around',
-        paddingTop: 10,
-        paddingBottom: 10,
+        height: totalHeight,
         width: '100%',
         position: 'fixed',
         zIndex: 100,
-        bottom: isVisible ? 0 : -height,
-        transition: 'bottom 0.2s ease-out',
+        bottom: 0,
+        ...(!isNarrowWidth && { display: 'none' }),
       }}
     >
-      <NavTab name="Budget" path="/budget" icon={Wallet} />
-      <NavTab name="Accounts" path="/accounts" icon={PiggyBank} />
-      <NavTab name="Transaction" path="/transactions/new" icon={Add} />
-      <NavTab name="Settings" path="/settings" icon={Cog} />
-    </div>
+      <View
+        style={{
+          flexDirection: 'row',
+          flexWrap: 'wrap',
+          height: totalHeight,
+          width: '100%',
+        }}
+      >
+        {[navTabs, bufferTabs]}
+      </View>
+    </animated.div>
   );
 }
 
@@ -60,9 +207,10 @@ type NavTabProps = {
   name: string;
   path: string;
   icon: ComponentType<NavTabIconProps>;
+  style?: CSSProperties;
 };
 
-function NavTab({ icon: TabIcon, name, path }: NavTabProps) {
+function NavTab({ icon: TabIcon, name, path, style }: NavTabProps) {
   return (
     <NavLink
       to={path}
@@ -73,6 +221,8 @@ function NavTab({ icon: TabIcon, name, path }: NavTabProps) {
         display: 'flex',
         flexDirection: 'column',
         textDecoration: 'none',
+        textAlign: 'center',
+        ...style,
       })}
     >
       <TabIcon width={22} height={22} />
diff --git a/upcoming-release-notes/1758.md b/upcoming-release-notes/1758.md
new file mode 100644
index 0000000000000000000000000000000000000000..6c53c11f4a13b8e38c4f5ebb34d7a811c5fbfdde
--- /dev/null
+++ b/upcoming-release-notes/1758.md
@@ -0,0 +1,6 @@
+---
+category: Enhancements
+authors: [joel-jeremy]
+---
+
+Swipe up mobile navbar to reveal more menus.
diff --git a/yarn.lock b/yarn.lock
index 84e07d99b375a76df8515d566ab29599d4171018..0c751260680c1176a77bf62156366ebc2bbe68c8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -74,6 +74,7 @@ __metadata:
     "@types/react-router-dom": ^5.3.3
     "@types/uuid": ^9.0.2
     "@types/webpack-bundle-analyzer": ^4.6.0
+    "@use-gesture/react": ^10.3.0
     chokidar: ^3.5.3
     cross-env: ^7.0.3
     date-fns: ^2.29.3
@@ -4993,6 +4994,24 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@use-gesture/core@npm:10.3.0":
+  version: 10.3.0
+  resolution: "@use-gesture/core@npm:10.3.0"
+  checksum: cd6782b0cf61ae2306ecee4bd3c30942251427c142e3fd3584778d86e1a93b27e087033246700b54c4ad7063aa78747dc793f0dbb7434925c306215fb18dee82
+  languageName: node
+  linkType: hard
+
+"@use-gesture/react@npm:^10.3.0":
+  version: 10.3.0
+  resolution: "@use-gesture/react@npm:10.3.0"
+  dependencies:
+    "@use-gesture/core": 10.3.0
+  peerDependencies:
+    react: ">= 16.8.0"
+  checksum: d43a2296e536ea8e4885ca082b7c554eabb0e19bb7f89b5db96e0511712c849db879de64c2746c94e3c9a5032e8918c90ace67fc023c754034d75b2ea3b727c4
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/ast@npm:1.11.5, @webassemblyjs/ast@npm:^1.11.5":
   version: 1.11.5
   resolution: "@webassemblyjs/ast@npm:1.11.5"