diff --git a/packages/desktop-client/e2e/page-models/account-page.js b/packages/desktop-client/e2e/page-models/account-page.js
index aa23d041867c2c68816d37b343ca4dab18793e43..01fb45dbac261c718b7b1a6b32ecef5e05d9e147 100644
--- a/packages/desktop-client/e2e/page-models/account-page.js
+++ b/packages/desktop-client/e2e/page-models/account-page.js
@@ -16,8 +16,8 @@ export class AccountPage {
     this.cancelTransactionButton = this.page.getByRole('button', {
       name: 'Cancel',
     });
-    this.menuButton = this.page.getByRole('button', {
-      name: 'Menu',
+    this.accountMenuButton = this.page.getByRole('button', {
+      name: 'Account menu',
     });
 
     this.transactionTable = this.page.getByTestId('transaction-table');
@@ -103,7 +103,7 @@ export class AccountPage {
    * Open the modal for closing the account.
    */
   async clickCloseAccount() {
-    await this.menuButton.click();
+    await this.accountMenuButton.click();
     await this.page.getByRole('button', { name: 'Close Account' }).click();
     return new CloseAccountModal(
       this.page.getByTestId('close-account-modal'),
diff --git a/packages/desktop-client/e2e/rules.test.js-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-4-chromium-linux.png b/packages/desktop-client/e2e/rules.test.js-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-4-chromium-linux.png
index 4a395ced02da2ccc74fd6b885ed51f39bb2e9532..d4b7313b410e7149c074209be960ed992930b223 100644
Binary files a/packages/desktop-client/e2e/rules.test.js-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-4-chromium-linux.png and b/packages/desktop-client/e2e/rules.test.js-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-4-chromium-linux.png differ
diff --git a/packages/desktop-client/src/components/FatalError.tsx b/packages/desktop-client/src/components/FatalError.tsx
index 58e2ec114bfdca98d66b8b81b6ada81acfa27942..724df4dbdf73e7dcd6de8a10ed6f31c6ea8ba81d 100644
--- a/packages/desktop-client/src/components/FatalError.tsx
+++ b/packages/desktop-client/src/components/FatalError.tsx
@@ -3,7 +3,7 @@ import React, { useState, type ReactNode } from 'react';
 import { LazyLoadFailedError } from 'loot-core/src/shared/errors';
 
 import { Block } from './common/Block';
-import { Button } from './common/Button';
+import { Button } from './common/Button2';
 import { Link } from './common/Link';
 import { Modal } from './common/Modal';
 import { Paragraph } from './common/Paragraph';
@@ -149,8 +149,8 @@ function SharedArrayBufferOverride() {
         I understand the risks, run Actual in the unsupported fallback mode
       </label>
       <Button
-        disabled={!understand}
-        onClick={() => {
+        isDisabled={!understand}
+        onPress={() => {
           window.localStorage.setItem('SharedArrayBufferOverride', 'true');
           window.location.reload();
         }}
@@ -191,7 +191,7 @@ export function FatalError({ error }: FatalErrorProps) {
         )}
 
         <Paragraph>
-          <Button onClick={() => window.Actual?.relaunch()}>Restart app</Button>
+          <Button onPress={() => window.Actual?.relaunch()}>Restart app</Button>
         </Paragraph>
         <Paragraph isLast={true} style={{ fontSize: 11 }}>
           <Link variant="text" onClick={() => setShowError(state => !state)}>
diff --git a/packages/desktop-client/src/components/LoggedInUser.tsx b/packages/desktop-client/src/components/LoggedInUser.tsx
index c9eba0badb8517bd6f02ca2323debb1241aac2c3..0df0d616f082e7f692c75d45e0210e3e487c1b22 100644
--- a/packages/desktop-client/src/components/LoggedInUser.tsx
+++ b/packages/desktop-client/src/components/LoggedInUser.tsx
@@ -7,7 +7,7 @@ import { type State } from 'loot-core/src/client/state-types';
 import { useActions } from '../hooks/useActions';
 import { theme, styles, type CSSProperties } from '../style';
 
-import { Button } from './common/Button';
+import { Button } from './common/Button2';
 import { Menu } from './common/Menu';
 import { Popover } from './common/Popover';
 import { Text } from './common/Text';
@@ -97,8 +97,8 @@ export function LoggedInUser({
     <View style={{ flexDirection: 'row', alignItems: 'center', ...style }}>
       <Button
         ref={triggerRef}
-        type="bare"
-        onClick={() => setMenuOpen(true)}
+        variant="bare"
+        onPress={() => setMenuOpen(true)}
         style={color && { color }}
       >
         {serverMessage()}
diff --git a/packages/desktop-client/src/components/ManageRules.tsx b/packages/desktop-client/src/components/ManageRules.tsx
index 79bc64ec414bc5e5eccae26804f0981429fde232..d627b98e367bf37bf65fc3145bda0a91655b6838 100644
--- a/packages/desktop-client/src/components/ManageRules.tsx
+++ b/packages/desktop-client/src/components/ManageRules.tsx
@@ -24,7 +24,7 @@ import { usePayees } from '../hooks/usePayees';
 import { useSelected, SelectedProvider } from '../hooks/useSelected';
 import { theme } from '../style';
 
-import { Button } from './common/Button';
+import { Button } from './common/Button2';
 import { Link } from './common/Link';
 import { Search } from './common/Search';
 import { Stack } from './common/Stack';
@@ -314,11 +314,11 @@ function ManageRulesContent({
         >
           <Stack direction="row" align="center" justify="flex-end" spacing={2}>
             {selectedInst.items.size > 0 && (
-              <Button onClick={onDeleteSelected}>
+              <Button onPress={onDeleteSelected}>
                 Delete {selectedInst.items.size} rules
               </Button>
             )}
-            <Button type="primary" onClick={onCreateRule}>
+            <Button variant="primary" onPress={onCreateRule}>
               Create new rule
             </Button>
           </Stack>
diff --git a/packages/desktop-client/src/components/NotesButton.tsx b/packages/desktop-client/src/components/NotesButton.tsx
index 901442b8c953c74bd00697e8ae50bc9832f406d3..de5c928d7ac516641a7036ab236c315133cc3a07 100644
--- a/packages/desktop-client/src/components/NotesButton.tsx
+++ b/packages/desktop-client/src/components/NotesButton.tsx
@@ -6,7 +6,7 @@ import { useNotes } from '../hooks/useNotes';
 import { SvgCustomNotesPaper } from '../icons/v2';
 import { type CSSProperties, theme } from '../style';
 
-import { Button } from './common/Button';
+import { Button } from './common/Button2';
 import { Popover } from './common/Popover';
 import { Tooltip } from './common/Tooltip';
 import { View } from './common/View';
@@ -52,7 +52,7 @@ export function NotesButton({
       <View style={{ flexShrink: 0 }}>
         <Button
           ref={triggerRef}
-          type="bare"
+          variant="bare"
           aria-label="View notes"
           className={!hasNotes && !isOpen ? 'hover-visible' : ''}
           style={{
@@ -61,8 +61,7 @@ export function NotesButton({
             ...(hasNotes && { display: 'flex !important' }),
             ...(isOpen && { color: theme.buttonNormalText }),
           }}
-          onClick={event => {
-            event.stopPropagation();
+          onPress={() => {
             setIsOpen(true);
           }}
         >
diff --git a/packages/desktop-client/src/components/Notifications.tsx b/packages/desktop-client/src/components/Notifications.tsx
index 1ed01bdce3f09e4e25c1ae937005fa64191c811c..185241524895bfd795fb55eb5d33201ff343ed9a 100644
--- a/packages/desktop-client/src/components/Notifications.tsx
+++ b/packages/desktop-client/src/components/Notifications.tsx
@@ -16,7 +16,7 @@ import { SvgDelete } from '../icons/v0';
 import { useResponsive } from '../ResponsiveProvider';
 import { styles, theme, type CSSProperties } from '../style';
 
-import { Button, ButtonWithLoading } from './common/Button';
+import { Button, ButtonWithLoading } from './common/Button2';
 import { Link } from './common/Link';
 import { Stack } from './common/Stack';
 import { Text } from './common/Text';
@@ -178,15 +178,15 @@ function Notification({
             : null}
           {button && (
             <ButtonWithLoading
-              type="bare"
-              loading={loading}
-              onClick={async () => {
+              variant="bare"
+              isLoading={loading}
+              onPress={async () => {
                 setLoading(true);
                 await button.action();
                 onRemove();
                 setLoading(false);
               }}
-              style={{
+              style={({ isHovered, isPressed }) => ({
                 backgroundColor: 'transparent',
                 border: `1px solid ${
                   positive
@@ -198,14 +198,16 @@ function Notification({
                 color: 'currentColor',
                 fontSize: 14,
                 flexShrink: 0,
-                '&:hover, &:active': {
-                  backgroundColor: positive
-                    ? theme.noticeBackground
-                    : error
-                      ? theme.errorBackground
-                      : theme.warningBackground,
-                },
-              }}
+                ...(isHovered || isPressed
+                  ? {
+                      backgroundColor: positive
+                        ? theme.noticeBackground
+                        : error
+                          ? theme.errorBackground
+                          : theme.warningBackground,
+                    }
+                  : {}),
+              })}
             >
               {button.title}
             </ButtonWithLoading>
@@ -213,10 +215,10 @@ function Notification({
         </Stack>
         {sticky && (
           <Button
-            type="bare"
+            variant="bare"
             aria-label="Close"
             style={{ flexShrink: 0, color: 'currentColor' }}
-            onClick={onRemove}
+            onPress={onRemove}
           >
             <SvgDelete style={{ width: 9, height: 9, color: 'currentColor' }} />
           </Button>
diff --git a/packages/desktop-client/src/components/ThemeSelector.tsx b/packages/desktop-client/src/components/ThemeSelector.tsx
index e07bcd13ac2dc07827f38809b0cabb72a18c6e9f..11ba1e817e8b6f3e7cfc8f7cd2cc8b16b3c48643 100644
--- a/packages/desktop-client/src/components/ThemeSelector.tsx
+++ b/packages/desktop-client/src/components/ThemeSelector.tsx
@@ -6,7 +6,7 @@ import { SvgMoonStars, SvgSun, SvgSystem } from '../icons/v2';
 import { useResponsive } from '../ResponsiveProvider';
 import { type CSSProperties, themeOptions, useTheme } from '../style';
 
-import { Button } from './common/Button';
+import { Button } from './common/Button2';
 import { Menu } from './common/Menu';
 import { Popover } from './common/Popover';
 
@@ -44,9 +44,9 @@ export function ThemeSelector({ style }: ThemeSelectorProps) {
     <>
       <Button
         ref={triggerRef}
-        type="bare"
+        variant="bare"
         aria-label="Switch theme"
-        onClick={() => setMenuOpen(true)}
+        onPress={() => setMenuOpen(true)}
         style={style}
       >
         <Icon style={{ width: 13, height: 13, color: 'inherit' }} />
diff --git a/packages/desktop-client/src/components/Titlebar.tsx b/packages/desktop-client/src/components/Titlebar.tsx
index 4336ef4e0f89e55113e852c8e1806c07493d80ad..9c25bbd10d0492d6a85dbc9f90f47866e954d457 100644
--- a/packages/desktop-client/src/components/Titlebar.tsx
+++ b/packages/desktop-client/src/components/Titlebar.tsx
@@ -24,7 +24,7 @@ import { theme, type CSSProperties, styles } from '../style';
 import { AccountSyncCheck } from './accounts/AccountSyncCheck';
 import { AnimatedRefresh } from './AnimatedRefresh';
 import { MonthCountSelector } from './budget/MonthCountSelector';
-import { Button } from './common/Button';
+import { Button } from './common/Button2';
 import { Link } from './common/Link';
 import { Text } from './common/Text';
 import { View } from './common/View';
@@ -78,9 +78,9 @@ function PrivacyButton({ style }: PrivacyButtonProps) {
 
   return (
     <Button
-      type="bare"
+      variant="bare"
       aria-label={`${isPrivacyEnabled ? 'Disable' : 'Enable'} privacy mode`}
-      onClick={() => setPrivacyEnabledPref(!isPrivacyEnabled)}
+      onPress={() => setPrivacyEnabledPref(!isPrivacyEnabled)}
       style={style}
     >
       {isPrivacyEnabled ? (
@@ -196,10 +196,10 @@ function SyncButton({ style, isMobile = false }: SyncButtonProps) {
 
   return (
     <Button
-      type="bare"
+      variant="bare"
       aria-label="Sync"
-      style={
-        isMobile
+      style={({ isHovered, isPressed }) => ({
+        ...(isMobile
           ? {
               ...style,
               WebkitAppRegion: 'none',
@@ -209,11 +209,11 @@ function SyncButton({ style, isMobile = false }: SyncButtonProps) {
               ...style,
               WebkitAppRegion: 'none',
               color: desktopColor,
-            }
-      }
-      hoveredStyle={hoveredStyle}
-      activeStyle={activeStyle}
-      onClick={sync}
+            }),
+        ...(isHovered ? hoveredStyle : {}),
+        ...(isPressed ? activeStyle : {}),
+      })}
+      onPress={sync}
     >
       {isMobile ? (
         syncState === 'error' ? (
@@ -281,14 +281,15 @@ export function Titlebar({ style }: TitlebarProps) {
     >
       {(floatingSidebar || sidebar.alwaysFloats) && (
         <Button
-          type="bare"
+          aria-label="Sidebar menu"
+          variant="bare"
           style={{ marginRight: 8 }}
-          onPointerEnter={e => {
+          onHoverStart={e => {
             if (e.pointerType === 'mouse') {
               sidebar.setHidden(false);
             }
           }}
-          onPointerUp={e => {
+          onPress={e => {
             if (e.pointerType !== 'mouse') {
               sidebar.setHidden(!sidebar.hidden);
             }
@@ -306,7 +307,7 @@ export function Titlebar({ style }: TitlebarProps) {
           path="/accounts"
           element={
             location.state?.goBack ? (
-              <Button type="bare" onClick={() => navigate(-1)}>
+              <Button variant="bare" onPress={() => navigate(-1)}>
                 <SvgArrowLeft
                   width={10}
                   height={10}
diff --git a/packages/desktop-client/src/components/UpdateNotification.tsx b/packages/desktop-client/src/components/UpdateNotification.tsx
index 2ce4831e24b633726a77c609e1148e519ca1797e..e2f9e60b7d62e36ef38167579c45daf368d5cf79 100644
--- a/packages/desktop-client/src/components/UpdateNotification.tsx
+++ b/packages/desktop-client/src/components/UpdateNotification.tsx
@@ -7,7 +7,7 @@ import { useActions } from '../hooks/useActions';
 import { SvgClose } from '../icons/v1';
 import { theme } from '../style';
 
-import { Button } from './common/Button';
+import { Button } from './common/Button2';
 import { Link } from './common/Link';
 import { Text } from './common/Text';
 import { View } from './common/View';
@@ -72,10 +72,10 @@ export function UpdateNotification() {
               </Link>
               )
               <Button
-                type="bare"
+                variant="bare"
                 aria-label="Close"
                 style={{ display: 'inline', padding: '1px 7px 2px 7px' }}
-                onClick={() => {
+                onPress={() => {
                   // Set a flag to never show an update notification again for this session
                   setAppState({
                     updateInfo: null,
diff --git a/packages/desktop-client/src/components/accounts/Header.jsx b/packages/desktop-client/src/components/accounts/Header.jsx
index d5591ccbf9a143e80cb40c659a4b778b0de4adfe..997f36298ac66388728bb14351fc0aad3a7e9570 100644
--- a/packages/desktop-client/src/components/accounts/Header.jsx
+++ b/packages/desktop-client/src/components/accounts/Header.jsx
@@ -379,7 +379,11 @@ export function AccountHeader({
           </Button>
           {account ? (
             <View>
-              <MenuButton ref={triggerRef} onClick={() => setMenuOpen(true)} />
+              <MenuButton
+                aria-label="Account menu"
+                ref={triggerRef}
+                onPress={() => setMenuOpen(true)}
+              />
 
               <Popover
                 triggerRef={triggerRef}
@@ -406,7 +410,11 @@ export function AccountHeader({
             </View>
           ) : (
             <View>
-              <MenuButton ref={triggerRef} onClick={() => setMenuOpen(true)} />
+              <MenuButton
+                aria-label="Account menu"
+                ref={triggerRef}
+                onPress={() => setMenuOpen(true)}
+              />
 
               <Popover
                 triggerRef={triggerRef}
diff --git a/packages/desktop-client/src/components/common/Button.tsx b/packages/desktop-client/src/components/common/Button.tsx
index c7a423397585d460768cdb87b5e2f7eb85607819..0cb88a7a638fa5e7e26100143d438892360bfea3 100644
--- a/packages/desktop-client/src/components/common/Button.tsx
+++ b/packages/desktop-client/src/components/common/Button.tsx
@@ -198,43 +198,42 @@ type ButtonWithLoadingProps = ButtonProps & {
   loading?: boolean;
 };
 
-export const ButtonWithLoading = forwardRef<
-  HTMLButtonElement,
-  ButtonWithLoadingProps
->((props, ref) => {
-  const { loading, children, ...buttonProps } = props;
-  return (
-    <Button
-      {...buttonProps}
-      ref={ref}
-      style={{ position: 'relative', ...buttonProps.style }}
-    >
-      {loading && (
+const ButtonWithLoading = forwardRef<HTMLButtonElement, ButtonWithLoadingProps>(
+  (props, ref) => {
+    const { loading, children, ...buttonProps } = props;
+    return (
+      <Button
+        {...buttonProps}
+        ref={ref}
+        style={{ position: 'relative', ...buttonProps.style }}
+      >
+        {loading && (
+          <View
+            style={{
+              position: 'absolute',
+              top: 0,
+              left: 0,
+              right: 0,
+              bottom: 0,
+              alignItems: 'center',
+              justifyContent: 'center',
+            }}
+          >
+            <AnimatedLoading style={{ width: 20, height: 20 }} />
+          </View>
+        )}
         <View
           style={{
-            position: 'absolute',
-            top: 0,
-            left: 0,
-            right: 0,
-            bottom: 0,
+            opacity: loading ? 0 : 1,
+            flexDirection: 'row',
             alignItems: 'center',
-            justifyContent: 'center',
           }}
         >
-          <AnimatedLoading style={{ width: 20, height: 20 }} />
+          {children}
         </View>
-      )}
-      <View
-        style={{
-          opacity: loading ? 0 : 1,
-          flexDirection: 'row',
-          alignItems: 'center',
-        }}
-      >
-        {children}
-      </View>
-    </Button>
-  );
-});
+      </Button>
+    );
+  },
+);
 
 ButtonWithLoading.displayName = 'ButtonWithLoading';
diff --git a/packages/desktop-client/src/components/common/Button2.tsx b/packages/desktop-client/src/components/common/Button2.tsx
index 78d3d1735ea2c1dbff0cfd004f3ba9ae167e4962..a48c1bb8dc3ebfa31fbf575370428e60905f4edb 100644
--- a/packages/desktop-client/src/components/common/Button2.tsx
+++ b/packages/desktop-client/src/components/common/Button2.tsx
@@ -1,9 +1,11 @@
 import React, { forwardRef, type ComponentPropsWithoutRef } from 'react';
 import {
+  type ButtonRenderProps as ReactAriaButtonRenderProps,
   Button as ReactAriaButton,
-  type ButtonProps as ReactAriaButtonProps,
 } from 'react-aria-components';
 
+import { css } from 'glamor';
+
 import { AnimatedLoading } from '../../icons/AnimatedLoading';
 import { type CSSProperties, styles, theme } from '../../style';
 
@@ -125,17 +127,10 @@ type ButtonVariant = 'normal' | 'primary' | 'bare' | 'menu' | 'menuSelected';
 
 export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
   (props, ref) => {
-    const {
-      children,
-      variant = 'normal',
-      bounce = true,
-      style,
-      isDisabled,
-      ...restProps
-    } = props;
+    const { children, variant = 'normal', bounce = true, ...restProps } = props;
 
     const variantWithDisabled: ButtonVariant | `${ButtonVariant}Disabled` =
-      isDisabled ? `${variant}Disabled` : variant;
+      props.isDisabled ? `${variant}Disabled` : variant;
 
     const hoveredStyle = {
       ...(variant !== 'bare' && styles.shadow),
@@ -143,39 +138,44 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
       color: textColorHover[variant],
       cursor: 'pointer',
     };
-    const pressedStyle = {
+    const activeStyle = {
       ..._getActiveStyles(variant, bounce),
     };
 
-    const buttonStyle: ComponentPropsWithoutRef<
-      typeof Button
-    >['style'] = props => ({
-      ...props.defaultStyle,
-      alignItems: 'center',
-      justifyContent: 'center',
-      flexShrink: 0,
-      padding: _getPadding(variant),
-      margin: 0,
-      overflow: 'hidden',
-      display: 'flex',
-      borderRadius: 4,
-      backgroundColor: backgroundColor[variantWithDisabled],
-      border: _getBorder(variant, variantWithDisabled),
-      color: textColor[variantWithDisabled],
-      transition: 'box-shadow .25s',
-      WebkitAppRegion: 'no-drag',
-      ...styles.smallText,
-      ...(props.isHovered && !isDisabled ? hoveredStyle : {}),
-      ...(props.isPressed && !isDisabled ? pressedStyle : {}),
-      ...(typeof style === 'function' ? style(props) : style),
-    });
+    const defaultButtonClassName: ReactAriaButtonClassNameFn = renderProps =>
+      String(
+        css({
+          alignItems: 'center',
+          justifyContent: 'center',
+          flexShrink: 0,
+          padding: _getPadding(variant),
+          margin: 0,
+          overflow: 'hidden',
+          display: 'flex',
+          borderRadius: 4,
+          backgroundColor: backgroundColor[variantWithDisabled],
+          border: _getBorder(variant, variantWithDisabled),
+          color: textColor[variantWithDisabled],
+          transition: 'box-shadow .25s',
+          WebkitAppRegion: 'no-drag',
+          ...styles.smallText,
+          ...(renderProps.isDisabled ? {} : { ':hover': hoveredStyle }),
+          ...(renderProps.isDisabled ? {} : { ':active': activeStyle }),
+        }),
+      );
+
+    const buttonClassName: ReactAriaButtonClassNameFn = renderProps =>
+      typeof props.className === 'function'
+        ? props.className(renderProps)
+        : props.className || '';
 
     return (
       <ReactAriaButton
         ref={ref}
-        isDisabled={isDisabled}
-        style={buttonStyle}
         {...restProps}
+        className={renderProps =>
+          `${renderProps.defaultClassName} ${defaultButtonClassName(renderProps)} ${buttonClassName(renderProps)}`
+        }
       >
         {children}
       </ReactAriaButton>
@@ -193,12 +193,15 @@ export const ButtonWithLoading = forwardRef<
   HTMLButtonElement,
   ButtonWithLoadingProps
 >((props, ref) => {
-  const { isLoading, children, ...buttonProps } = props;
+  const { isLoading, children, style, ...buttonProps } = props;
   return (
     <Button
       {...buttonProps}
       ref={ref}
-      style={{ position: 'relative', ...buttonProps.style }}
+      style={buttonRenderProps => ({
+        position: 'relative',
+        ...(typeof style === 'function' ? style(buttonRenderProps) : style),
+      })}
     >
       {renderProps => (
         <>
@@ -233,3 +236,10 @@ export const ButtonWithLoading = forwardRef<
 });
 
 ButtonWithLoading.displayName = 'ButtonWithLoading';
+
+type ReactAriaButtonClassNameFn = Extract<
+  ComponentPropsWithoutRef<typeof ReactAriaButton>['className'],
+  (
+    renderProps: ReactAriaButtonRenderProps & { defaultClassName: string },
+  ) => string
+>;
diff --git a/packages/desktop-client/src/components/common/MenuButton.tsx b/packages/desktop-client/src/components/common/MenuButton.tsx
index 452c6b642cef6a9d3a9c57d8b0fc6e96391b3863..bf55a955cc52120a1772da4b77ac2b93421a919d 100644
--- a/packages/desktop-client/src/components/common/MenuButton.tsx
+++ b/packages/desktop-client/src/components/common/MenuButton.tsx
@@ -1,25 +1,15 @@
-import React, { forwardRef } from 'react';
+import React, { type ComponentPropsWithoutRef, forwardRef } from 'react';
 
 import { SvgDotsHorizontalTriple } from '../../icons/v1';
-import { type CSSProperties } from '../../style';
 
-import { Button } from './Button';
+import { Button } from './Button2';
 
-type MenuButtonProps = {
-  onClick: () => void;
-  style?: CSSProperties;
-};
+type MenuButtonProps = ComponentPropsWithoutRef<typeof Button>;
 
 export const MenuButton = forwardRef<HTMLButtonElement, MenuButtonProps>(
-  ({ onClick, style }, ref) => {
+  (props, ref) => {
     return (
-      <Button
-        ref={ref}
-        type="bare"
-        onClick={onClick}
-        aria-label="Menu"
-        style={style}
-      >
+      <Button ref={ref} variant="bare" aria-label="Menu" {...props}>
         <SvgDotsHorizontalTriple
           width={15}
           height={15}
diff --git a/packages/desktop-client/src/components/reports/reports/ListCardsPopover.tsx b/packages/desktop-client/src/components/reports/reports/ListCardsPopover.tsx
index c0daf34b0edd64eceb1b2b1ce72ac86cae9676c7..7b2a2817ba240b28827eabf0571a42227157e600 100644
--- a/packages/desktop-client/src/components/reports/reports/ListCardsPopover.tsx
+++ b/packages/desktop-client/src/components/reports/reports/ListCardsPopover.tsx
@@ -47,8 +47,9 @@ export function ListCardsPopover({
   return (
     <>
       <MenuButton
+        aria-label="Report menu"
         ref={triggerRef}
-        onClick={() =>
+        onPress={() =>
           onMenuOpen(report.id === undefined ? '' : report.id, true)
         }
         style={{
diff --git a/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx b/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx
index 27df5bf61666ee482a40b63a364640b29be80915..20244423f917711a611bb80f7bbe65d250927950 100644
--- a/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx
+++ b/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx
@@ -7,7 +7,7 @@ import { getRecurringDescription } from 'loot-core/src/shared/schedules';
 import { useDateFormat } from '../../hooks/useDateFormat';
 import { SvgAdd, SvgSubtract } from '../../icons/v0';
 import { theme } from '../../style';
-import { Button } from '../common/Button';
+import { Button } from '../common/Button2';
 import { Input } from '../common/Input';
 import { Menu } from '../common/Menu';
 import { Popover } from '../common/Popover';
@@ -241,10 +241,10 @@ function MonthlyPatterns({ config, dispatch }) {
             buttonStyle={{ flex: 1, marginRight: 10 }}
           />
           <Button
-            type="bare"
+            variant="bare"
             aria-label="Remove recurrence"
             style={{ padding: 7 }}
-            onClick={() =>
+            onPress={() =>
               dispatch({
                 type: 'remove-recurrence',
                 recurrence,
@@ -254,10 +254,10 @@ function MonthlyPatterns({ config, dispatch }) {
             <SvgSubtract style={{ width: 8, height: 8 }} />
           </Button>
           <Button
-            type="bare"
+            variant="bare"
             aria-label="Add recurrence"
             style={{ padding: 7, marginLeft: 5 }}
-            onClick={() => dispatch({ type: 'add-recurrence' })}
+            onPress={() => dispatch({ type: 'add-recurrence' })}
           >
             <SvgAdd style={{ width: 10, height: 10 }} />
           </Button>
@@ -381,7 +381,7 @@ function RecurringScheduleTooltip({ config: currentConfig, onClose, onSave }) {
               backgroundColor: theme.tableBackground,
               ':hover': { backgroundColor: theme.tableBackground },
             }}
-            onClick={() => dispatch({ type: 'add-recurrence' })}
+            onPress={() => dispatch({ type: 'add-recurrence' })}
           >
             Add specific days
           </Button>
@@ -444,10 +444,10 @@ function RecurringScheduleTooltip({ config: currentConfig, onClose, onSave }) {
       <div
         style={{ display: 'flex', marginTop: 15, justifyContent: 'flex-end' }}
       >
-        <Button onClick={onClose}>Cancel</Button>
+        <Button onPress={onClose}>Cancel</Button>
         <Button
-          type="primary"
-          onClick={() => onSave(unparseConfig(config))}
+          variant="primary"
+          onPress={() => onSave(unparseConfig(config))}
           style={{ marginLeft: 10 }}
         >
           Apply
@@ -472,7 +472,7 @@ export function RecurringSchedulePicker({ value, buttonStyle, onChange }) {
       <Button
         ref={triggerRef}
         style={{ textAlign: 'left', ...buttonStyle }}
-        onClick={() => setIsOpen(true)}
+        onPress={() => setIsOpen(true)}
       >
         {value
           ? getRecurringDescription(value, dateFormat)
diff --git a/packages/desktop-client/src/components/sidebar/Sidebar.tsx b/packages/desktop-client/src/components/sidebar/Sidebar.tsx
index f39629292af86df706218a96b6f92c91dac8ae6d..4f76a71ea73cbc85e292d75d2afd5e3261cc1073 100644
--- a/packages/desktop-client/src/components/sidebar/Sidebar.tsx
+++ b/packages/desktop-client/src/components/sidebar/Sidebar.tsx
@@ -20,7 +20,7 @@ import { SvgReports, SvgWallet } from '../../icons/v1';
 import { SvgCalendar } from '../../icons/v2';
 import { useResponsive } from '../../ResponsiveProvider';
 import { styles, theme } from '../../style';
-import { Button } from '../common/Button';
+import { Button } from '../common/Button2';
 import { InitialFocus } from '../common/InitialFocus';
 import { Input } from '../common/Input';
 import { Menu } from '../common/Menu';
@@ -238,15 +238,15 @@ function EditableBudgetName() {
     <>
       <Button
         ref={triggerRef}
-        type="bare"
-        color={theme.buttonNormalBorder}
+        variant="bare"
         style={{
+          color: theme.buttonNormalBorder,
           fontSize: 16,
           fontWeight: 500,
           marginLeft: -5,
           flex: '0 auto',
         }}
-        onClick={() => setMenuOpen(true)}
+        onPress={() => setMenuOpen(true)}
       >
         <Text style={{ whiteSpace: 'nowrap', overflow: 'hidden' }}>
           {budgetName || 'A budget has no name'}
diff --git a/packages/desktop-client/src/components/sidebar/ToggleButton.tsx b/packages/desktop-client/src/components/sidebar/ToggleButton.tsx
index 68375191e5dc90571d95a4700eb78b32e942a815..bf7c79f5dc84bc3f061787aba79626c1d29f9dda 100644
--- a/packages/desktop-client/src/components/sidebar/ToggleButton.tsx
+++ b/packages/desktop-client/src/components/sidebar/ToggleButton.tsx
@@ -1,14 +1,14 @@
-import React, { type MouseEventHandler } from 'react';
+import React, { type ComponentPropsWithoutRef } from 'react';
 
 import { SvgPin } from '../../icons/v1';
 import { SvgArrowButtonLeft1 } from '../../icons/v2';
 import { type CSSProperties, theme } from '../../style';
-import { Button } from '../common/Button';
+import { Button } from '../common/Button2';
 import { View } from '../common/View';
 
 type ToggleButtonProps = {
   isFloating: boolean;
-  onFloat: MouseEventHandler<HTMLButtonElement>;
+  onFloat: ComponentPropsWithoutRef<typeof Button>['onPress'];
   style?: CSSProperties;
 };
 
@@ -20,10 +20,10 @@ export function ToggleButton({
   return (
     <View className="float" style={{ ...style, flexShrink: 0 }}>
       <Button
-        type="bare"
+        variant="bare"
         aria-label={`${isFloating ? 'Pin' : 'Unpin'} sidebar`}
-        onClick={onFloat}
-        color={theme.buttonMenuBorder}
+        onPress={onFloat}
+        style={{ color: theme.buttonMenuBorder }}
       >
         {isFloating ? (
           <SvgPin
diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx
index e8a88718ea08e0a3f42bd4ea0a1b6e47af61d721..34aa417ae512b4da804a89991df5846f8aa36aaa 100644
--- a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx
+++ b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx
@@ -61,7 +61,7 @@ import { styles, theme } from '../../style';
 import { AccountAutocomplete } from '../autocomplete/AccountAutocomplete';
 import { CategoryAutocomplete } from '../autocomplete/CategoryAutocomplete';
 import { PayeeAutocomplete } from '../autocomplete/PayeeAutocomplete';
-import { Button } from '../common/Button';
+import { Button } from '../common/Button2';
 import { Popover } from '../common/Popover';
 import { Text } from '../common/Text';
 import { Tooltip } from '../common/Tooltip';
@@ -468,7 +468,7 @@ function HeaderCell({
       }}
       unexposedContent={({ value: cellValue }) =>
         onClick ? (
-          <Button type="bare" onClick={onClick} style={style}>
+          <Button variant="bare" onPress={onClick} style={style}>
             <UnexposedCellContent value={cellValue} />
             {icon === 'asc' && (
               <SvgArrowDown width={10} height={10} style={{ marginLeft: 5 }} />
@@ -747,33 +747,36 @@ function PayeeIcons({
       ? scheduleData.schedules.find(s => s.id === scheduleId)
       : null;
 
+  const buttonStyle = useMemo(
+    () => ({
+      marginLeft: -5,
+      marginRight: 2,
+      width: 23,
+      height: 23,
+      color: 'inherit',
+    }),
+    [],
+  );
+
+  const scheduleIconStyle = useMemo(() => ({ width: 13, height: 13 }), []);
+
+  const transferIconStyle = useMemo(() => ({ width: 10, height: 10 }), []);
+
   if (schedule == null && transferAccount == null) {
     // Neither a valid scheduled transaction nor a transfer.
     return null;
   }
 
-  const buttonStyle = {
-    marginLeft: -5,
-    marginRight: 2,
-    width: 23,
-    height: 23,
-    color: 'inherit',
-  };
-
-  const scheduleIconStyle = { width: 13, height: 13 };
-
-  const transferIconStyle = { width: 10, height: 10 };
-
   const recurring = schedule && schedule._date && !!schedule._date.frequency;
 
   return (
     <>
       {schedule && (
         <Button
-          type="bare"
+          variant="bare"
+          aria-label="See schedule details"
           style={buttonStyle}
-          onClick={e => {
-            e.stopPropagation();
+          onPress={() => {
             onNavigateToSchedule(scheduleId);
           }}
         >
@@ -786,11 +789,10 @@ function PayeeIcons({
       )}
       {transferAccount && (
         <Button
-          type="bare"
-          aria-label="Transfer"
+          variant="bare"
+          aria-label="See transfer account"
           style={buttonStyle}
-          onClick={e => {
-            e.stopPropagation();
+          onPress={() => {
             if (!isTemporaryId(transaction.id)) {
               onNavigateToTransferAccount(transferAccount.id);
             }
@@ -1571,18 +1573,18 @@ function TransactionError({
             </Text>
             <View style={{ flex: 1 }} />
             <Button
-              type="normal"
+              variant="normal"
               style={{ marginLeft: 15 }}
-              onClick={onDistributeRemainder}
+              onPress={onDistributeRemainder}
               data-testid="distribute-split-button"
-              disabled={!canDistributeRemainder}
+              isDisabled={!canDistributeRemainder}
             >
               Distribute
             </Button>
             <Button
-              type="primary"
+              variant="primary"
               style={{ marginLeft: 10, padding: '4px 10px' }}
-              onClick={onAddSplit}
+              onPress={onAddSplit}
               data-testid="add-split-button"
             >
               Add Split
@@ -1709,7 +1711,7 @@ function NewTransaction({
       >
         <Button
           style={{ marginRight: 10, padding: '4px 10px' }}
-          onClick={() => onClose()}
+          onPress={() => onClose()}
           data-testid="cancel-button"
         >
           Cancel
@@ -1726,9 +1728,9 @@ function NewTransaction({
           />
         ) : (
           <Button
-            type="primary"
+            variant="primary"
             style={{ padding: '4px 10px' }}
-            onClick={onAdd}
+            onPress={onAdd}
             data-testid="add-button"
           >
             Add
@@ -2500,9 +2502,9 @@ function notesTagFormatter(notes, onNotesTagClick) {
             return (
               <span key={`${validTag}${ti}`}>
                 <Button
-                  type="bare"
+                  variant="bare"
                   key={i}
-                  style={{
+                  style={({ isHovered }) => ({
                     display: 'inline-flex',
                     padding: '3px 7px',
                     borderRadius: 16,
@@ -2510,13 +2512,11 @@ function notesTagFormatter(notes, onNotesTagClick) {
                     backgroundColor: theme.noteTagBackground,
                     color: theme.noteTagText,
                     cursor: 'pointer',
-                  }}
-                  hoveredStyle={{
-                    backgroundColor: theme.noteTagBackgroundHover,
-                    color: theme.noteTagText,
-                  }}
-                  onClick={e => {
-                    e.stopPropagation();
+                    ...(isHovered
+                      ? { backgroundColor: theme.noteTagBackgroundHover }
+                      : {}),
+                  })}
+                  onPress={() => {
                     onNotesTagClick?.(validTag);
                   }}
                 >
diff --git a/upcoming-release-notes/2984.md b/upcoming-release-notes/2984.md
new file mode 100644
index 0000000000000000000000000000000000000000..9dae3c74012379b2d1057ef87a9e8c8a15eb06de
--- /dev/null
+++ b/upcoming-release-notes/2984.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [joel-jeremy]
+---
+
+Use new react-aria-components based Button on sidebar, notifications, transactions, recurring schedule picker, etc.