From 5e3485a8e299f6b1438cdd6ae5a377b2419d2c65 Mon Sep 17 00:00:00 2001
From: Robert Dyer <rdyer@unl.edu>
Date: Thu, 15 Aug 2024 08:36:09 -0500
Subject: [PATCH] Automatically focus inputs, or the primary button, in modals.
 (#2974)

* Automatically focus inputs, or the primary button, in modals.

* Set focus on more modals.

* focus mobile transaction edits

* add release note

* fix linter

* fix linter
---
 .../src/components/accounts/Account.jsx       |  7 +++++-
 .../components/accounts/AccountSyncCheck.jsx  |  1 +
 .../src/components/accounts/Reconcile.jsx     |  2 +-
 .../src/components/manager/ImportActual.tsx   |  1 +
 .../src/components/manager/ImportYNAB4.tsx    |  1 +
 .../src/components/manager/ImportYNAB5.tsx    |  1 +
 .../src/components/manager/WelcomeScreen.tsx  |  2 +-
 .../mobile/transactions/TransactionEdit.jsx   |  2 +-
 .../components/modals/CloseAccountModal.tsx   |  1 +
 .../modals/ConfirmCategoryDelete.tsx          |  3 ++-
 .../modals/ConfirmTransactionDelete.tsx       | 23 +++++++++--------
 .../modals/ConfirmTransactionEdit.tsx         | 23 +++++++++--------
 .../modals/ConfirmUnlinkAccount.tsx           | 21 +++++++++-------
 .../components/modals/CreateAccountModal.tsx  | 25 +++++++++++--------
 .../modals/GoCardlessExternalMsg.tsx          |  2 ++
 .../modals/GoCardlessInitialise.tsx           | 21 +++++++++-------
 .../components/modals/ImportTransactions.jsx  |  1 +
 .../components/modals/MergeUnusedPayees.jsx   |  1 +
 .../components/modals/SimpleFinInitialise.tsx |  1 +
 .../components/reports/SaveReportDelete.tsx   |  4 +--
 .../schedules/PostsOfflineNotification.jsx    |  1 +
 .../components/schedules/ScheduleDetails.jsx  | 21 +++++++++-------
 .../src/components/schedules/ScheduleLink.tsx | 19 ++++++++------
 .../select/RecurringSchedulePicker.jsx        | 19 ++++++++------
 upcoming-release-notes/2974.md                |  6 +++++
 25 files changed, 128 insertions(+), 81 deletions(-)
 create mode 100644 upcoming-release-notes/2974.md

diff --git a/packages/desktop-client/src/components/accounts/Account.jsx b/packages/desktop-client/src/components/accounts/Account.jsx
index 06fddb35e..3153fd749 100644
--- a/packages/desktop-client/src/components/accounts/Account.jsx
+++ b/packages/desktop-client/src/components/accounts/Account.jsx
@@ -75,7 +75,12 @@ function EmptyMessage({ onAdd }) {
           manage it locally yourself.
         </Text>
 
-        <Button variant="primary" style={{ marginTop: 20 }} onPress={onAdd}>
+        <Button
+          variant="primary"
+          style={{ marginTop: 20 }}
+          autoFocus
+          onPress={onAdd}
+        >
           Add account
         </Button>
 
diff --git a/packages/desktop-client/src/components/accounts/AccountSyncCheck.jsx b/packages/desktop-client/src/components/accounts/AccountSyncCheck.jsx
index 046f047eb..e8812ecad 100644
--- a/packages/desktop-client/src/components/accounts/AccountSyncCheck.jsx
+++ b/packages/desktop-client/src/components/accounts/AccountSyncCheck.jsx
@@ -140,6 +140,7 @@ export function AccountSyncCheck() {
               <Button onPress={unlink}>Unlink</Button>
               <Button
                 variant="primary"
+                autoFocus
                 onPress={reauth}
                 style={{ marginLeft: 5 }}
               >
diff --git a/packages/desktop-client/src/components/accounts/Reconcile.jsx b/packages/desktop-client/src/components/accounts/Reconcile.jsx
index ab7127858..5ebcd31fa 100644
--- a/packages/desktop-client/src/components/accounts/Reconcile.jsx
+++ b/packages/desktop-client/src/components/accounts/Reconcile.jsx
@@ -78,7 +78,7 @@ export function ReconcilingMessage({
           </View>
         )}
         <View style={{ marginLeft: 15 }}>
-          <Button variant="primary" onPress={onDone}>
+          <Button variant="primary" autoFocus onPress={onDone}>
             Done Reconciling
           </Button>
         </View>
diff --git a/packages/desktop-client/src/components/manager/ImportActual.tsx b/packages/desktop-client/src/components/manager/ImportActual.tsx
index 360f7d7a4..78305fdeb 100644
--- a/packages/desktop-client/src/components/manager/ImportActual.tsx
+++ b/packages/desktop-client/src/components/manager/ImportActual.tsx
@@ -84,6 +84,7 @@ export function ImportActual({ modalProps }: ImportProps) {
             <View style={{ alignSelf: 'center' }}>
               <ButtonWithLoading
                 variant="primary"
+                autoFocus
                 isLoading={importing}
                 onPress={onImport}
               >
diff --git a/packages/desktop-client/src/components/manager/ImportYNAB4.tsx b/packages/desktop-client/src/components/manager/ImportYNAB4.tsx
index e145977c8..b0a8478ba 100644
--- a/packages/desktop-client/src/components/manager/ImportYNAB4.tsx
+++ b/packages/desktop-client/src/components/manager/ImportYNAB4.tsx
@@ -73,6 +73,7 @@ export function ImportYNAB4({ modalProps }: ImportProps) {
             <View>
               <ButtonWithLoading
                 variant="primary"
+                autoFocus
                 isLoading={importing}
                 onPress={onImport}
               >
diff --git a/packages/desktop-client/src/components/manager/ImportYNAB5.tsx b/packages/desktop-client/src/components/manager/ImportYNAB5.tsx
index 3876f337a..5771e99c9 100644
--- a/packages/desktop-client/src/components/manager/ImportYNAB5.tsx
+++ b/packages/desktop-client/src/components/manager/ImportYNAB5.tsx
@@ -83,6 +83,7 @@ export function ImportYNAB5({ modalProps }: ImportProps) {
             <View>
               <ButtonWithLoading
                 variant="primary"
+                autoFocus
                 isLoading={importing}
                 onPress={onImport}
               >
diff --git a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx
index 8dcc9f4f3..71fda245e 100644
--- a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx
+++ b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx
@@ -90,7 +90,7 @@ export function WelcomeScreen() {
           <Button onPress={() => createBudget({ testMode: true })}>
             {t('View demo')}
           </Button>
-          <Button variant="primary" onPress={() => createBudget()}>
+          <Button variant="primary" autoFocus onPress={() => createBudget()}>
             {t('Start fresh')}
           </Button>
         </View>
diff --git a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx
index f80218f6b..3cb7db764 100644
--- a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx
+++ b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx
@@ -460,7 +460,7 @@ const TransactionEditInner = memo(function TransactionEditInner({
 
   const { editingField, onRequestActiveEdit, onClearActiveEdit } =
     useSingleActiveEditForm();
-  const [totalAmountFocused, setTotalAmountFocused] = useState(false);
+  const [totalAmountFocused, setTotalAmountFocused] = useState(true);
   const childTransactionElementRefMap = useRef({});
 
   const payeesById = useMemo(() => groupById(payees), [payees]);
diff --git a/packages/desktop-client/src/components/modals/CloseAccountModal.tsx b/packages/desktop-client/src/components/modals/CloseAccountModal.tsx
index c1668a701..c51ec6dba 100644
--- a/packages/desktop-client/src/components/modals/CloseAccountModal.tsx
+++ b/packages/desktop-client/src/components/modals/CloseAccountModal.tsx
@@ -151,6 +151,7 @@ export function CloseAccountModal({
                       value={transferAccountId}
                       inputProps={{
                         placeholder: 'Select account...',
+                        autoFocus: true,
                         ...(isNarrowWidth && {
                           value: transferAccount?.name || '',
                           style: {
diff --git a/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx b/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx
index 7713a6a09..d1191938f 100644
--- a/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx
+++ b/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx
@@ -67,7 +67,7 @@ export function ConfirmCategoryDelete({
             {group ? (
               <Block>
                 Categories in the group <strong>{group.name}</strong> are used
-                by existing transaction
+                by existing transactions
                 {!isIncome &&
                   ' or it has a positive leftover balance currently'}
                 . <strong>Are you sure you want to delete it?</strong> If so,
@@ -115,6 +115,7 @@ export function ConfirmCategoryDelete({
                           }))
                   }
                   value={transferCategory}
+                  focused={true}
                   inputProps={{
                     placeholder: 'Select category...',
                   }}
diff --git a/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx b/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx
index 26f2ecaf2..7c1b43ef8 100644
--- a/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx
+++ b/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx
@@ -3,6 +3,7 @@ import React from 'react';
 import { useResponsive } from '../../ResponsiveProvider';
 import { styles } from '../../style';
 import { Button } from '../common/Button2';
+import { InitialFocus } from '../common/InitialFocus';
 import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2';
 import { Paragraph } from '../common/Paragraph';
 import { View } from '../common/View';
@@ -48,16 +49,18 @@ export function ConfirmTransactionDelete({
               >
                 Cancel
               </Button>
-              <Button
-                variant="primary"
-                style={narrowButtonStyle}
-                onPress={() => {
-                  onConfirm();
-                  close();
-                }}
-              >
-                Delete
-              </Button>
+              <InitialFocus>
+                <Button
+                  variant="primary"
+                  style={narrowButtonStyle}
+                  onPress={() => {
+                    onConfirm();
+                    close();
+                  }}
+                >
+                  Delete
+                </Button>
+              </InitialFocus>
             </View>
           </View>
         </>
diff --git a/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx b/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx
index 6b445bda6..4d4568591 100644
--- a/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx
+++ b/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx
@@ -3,6 +3,7 @@ import React from 'react';
 
 import { Block } from '../common/Block';
 import { Button } from '../common/Button2';
+import { InitialFocus } from '../common/InitialFocus';
 import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2';
 import { View } from '../common/View';
 
@@ -88,16 +89,18 @@ export function ConfirmTransactionEdit({
                 >
                   Cancel
                 </Button>
-                <Button
-                  aria-label="Confirm"
-                  variant="primary"
-                  onPress={() => {
-                    close();
-                    onConfirm();
-                  }}
-                >
-                  Confirm
-                </Button>
+                <InitialFocus>
+                  <Button
+                    aria-label="Confirm"
+                    variant="primary"
+                    onPress={() => {
+                      close();
+                      onConfirm();
+                    }}
+                  >
+                    Confirm
+                  </Button>
+                </InitialFocus>
               </View>
             </View>
           </View>
diff --git a/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx b/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx
index e3d5fb535..6a51ded8b 100644
--- a/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx
+++ b/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx
@@ -1,6 +1,7 @@
 import React from 'react';
 
 import { Button } from '../common/Button2';
+import { InitialFocus } from '../common/InitialFocus';
 import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2';
 import { Paragraph } from '../common/Paragraph';
 import { View } from '../common/View';
@@ -44,15 +45,17 @@ export function ConfirmUnlinkAccount({
               <Button style={{ marginRight: 10 }} onPress={close}>
                 Cancel
               </Button>
-              <Button
-                variant="primary"
-                onPress={() => {
-                  onUnlink();
-                  close();
-                }}
-              >
-                Unlink
-              </Button>
+              <InitialFocus>
+                <Button
+                  variant="primary"
+                  onPress={() => {
+                    onUnlink();
+                    close();
+                  }}
+                >
+                  Unlink
+                </Button>
+              </InitialFocus>
             </View>
           </View>
         </>
diff --git a/packages/desktop-client/src/components/modals/CreateAccountModal.tsx b/packages/desktop-client/src/components/modals/CreateAccountModal.tsx
index c23e67aaf..ed88da037 100644
--- a/packages/desktop-client/src/components/modals/CreateAccountModal.tsx
+++ b/packages/desktop-client/src/components/modals/CreateAccountModal.tsx
@@ -12,6 +12,7 @@ import { type SyncServerStatus } from '../../hooks/useSyncServerStatus';
 import { SvgDotsHorizontalTriple } from '../../icons/v1';
 import { theme } from '../../style';
 import { Button, ButtonWithLoading } from '../common/Button2';
+import { InitialFocus } from '../common/InitialFocus';
 import { Link } from '../common/Link';
 import { Menu } from '../common/Menu';
 import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2';
@@ -186,17 +187,19 @@ export function CreateAccountModal({
           <View style={{ maxWidth: 500, gap: 30, color: theme.pageText }}>
             {upgradingAccountId == null && (
               <View style={{ gap: 10 }}>
-                <Button
-                  variant="primary"
-                  style={{
-                    padding: '10px 0',
-                    fontSize: 15,
-                    fontWeight: 600,
-                  }}
-                  onPress={onCreateLocalAccount}
-                >
-                  Create local account
-                </Button>
+                <InitialFocus>
+                  <Button
+                    variant="primary"
+                    style={{
+                      padding: '10px 0',
+                      fontSize: 15,
+                      fontWeight: 600,
+                    }}
+                    onPress={onCreateLocalAccount}
+                  >
+                    Create local account
+                  </Button>
+                </InitialFocus>
                 <View style={{ lineHeight: '1.4em', fontSize: 15 }}>
                   <Text>
                     <strong>Create a local account</strong> if you want to add
diff --git a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx
index 2dbbc049e..ef3bef944 100644
--- a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx
+++ b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx
@@ -206,6 +206,7 @@ export function GoCardlessExternalMsg({
         <View style={{ flexDirection: 'row', gap: 10, alignItems: 'center' }}>
           <Button
             variant="primary"
+            autoFocus
             style={{
               padding: '10px 0',
               fontSize: 15,
@@ -272,6 +273,7 @@ export function GoCardlessExternalMsg({
             ) : success ? (
               <Button
                 variant="primary"
+                autoFocus
                 style={{
                   padding: '10px 0',
                   fontSize: 15,
diff --git a/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx b/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx
index fc91a66a1..6906b26c8 100644
--- a/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx
+++ b/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx
@@ -5,6 +5,7 @@ import { send } from 'loot-core/src/platform/client/fetch';
 
 import { Error } from '../alerts';
 import { ButtonWithLoading } from '../common/Button2';
+import { InitialFocus } from '../common/InitialFocus';
 import { Input } from '../common/Input';
 import { Link } from '../common/Link';
 import {
@@ -78,15 +79,17 @@ export const GoCardlessInitialise = ({
 
             <FormField>
               <FormLabel title="Secret ID:" htmlFor="secret-id-field" />
-              <Input
-                id="secret-id-field"
-                type="password"
-                value={secretId}
-                onChangeValue={value => {
-                  setSecretId(value);
-                  setIsValid(true);
-                }}
-              />
+              <InitialFocus>
+                <Input
+                  id="secret-id-field"
+                  type="password"
+                  value={secretId}
+                  onChangeValue={value => {
+                    setSecretId(value);
+                    setIsValid(true);
+                  }}
+                />
+              </InitialFocus>
             </FormField>
 
             <FormField>
diff --git a/packages/desktop-client/src/components/modals/ImportTransactions.jsx b/packages/desktop-client/src/components/modals/ImportTransactions.jsx
index 88ffb4788..d3f281a59 100644
--- a/packages/desktop-client/src/components/modals/ImportTransactions.jsx
+++ b/packages/desktop-client/src/components/modals/ImportTransactions.jsx
@@ -1719,6 +1719,7 @@ export function ImportTransactions({ options }) {
             >
               <ButtonWithLoading
                 variant="primary"
+                autoFocus
                 isDisabled={
                   transactions?.filter(trans => !trans.isMatchedTransaction)
                     .length === 0
diff --git a/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx b/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx
index 2a8256869..0b236b598 100644
--- a/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx
+++ b/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx
@@ -151,6 +151,7 @@ export function MergeUnusedPayees({ payeeIds, targetPayeeId }) {
             <ModalButtons style={{ marginTop: 20 }} focusButton>
               <Button
                 variant="primary"
+                autoFocus
                 style={{ marginRight: 10 }}
                 onPress={() => {
                   onMerge();
diff --git a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx
index 21613af5c..f6587c726 100644
--- a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx
+++ b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx
@@ -88,6 +88,7 @@ export const SimpleFinInitialise = ({
           <ModalButtons>
             <ButtonWithLoading
               variant="primary"
+              autoFocus
               isLoading={isLoading}
               onPress={() => {
                 onSubmit(close);
diff --git a/packages/desktop-client/src/components/reports/SaveReportDelete.tsx b/packages/desktop-client/src/components/reports/SaveReportDelete.tsx
index 7a8da58a5..436b3ef95 100644
--- a/packages/desktop-client/src/components/reports/SaveReportDelete.tsx
+++ b/packages/desktop-client/src/components/reports/SaveReportDelete.tsx
@@ -21,7 +21,7 @@ export function SaveReportDelete({
     <>
       <View style={{ align: 'center' }}>
         <Text style={{ color: theme.errorText, marginBottom: 5 }}>
-          Do you want to delete report:
+          Are you sure you want to delete report:
         </Text>
         <View>{name}</View>
       </View>
@@ -33,7 +33,7 @@ export function SaveReportDelete({
         style={{ marginTop: 15 }}
       >
         <View style={{ flex: 1 }} />
-        <Button variant="primary" onPress={onDelete}>
+        <Button variant="primary" autoFocus onPress={onDelete}>
           Yes
         </Button>
         <Button variant="primary" onPress={onClose}>
diff --git a/packages/desktop-client/src/components/schedules/PostsOfflineNotification.jsx b/packages/desktop-client/src/components/schedules/PostsOfflineNotification.jsx
index b19c0dc9e..29ad0f5da 100644
--- a/packages/desktop-client/src/components/schedules/PostsOfflineNotification.jsx
+++ b/packages/desktop-client/src/components/schedules/PostsOfflineNotification.jsx
@@ -81,6 +81,7 @@ export function PostsOfflineNotification() {
             <Button onPress={close}>Decide later</Button>
             <Button
               variant="primary"
+              autoFocus
               onPress={() => {
                 onPost();
                 close();
diff --git a/packages/desktop-client/src/components/schedules/ScheduleDetails.jsx b/packages/desktop-client/src/components/schedules/ScheduleDetails.jsx
index a91aeb3b6..67900bf27 100644
--- a/packages/desktop-client/src/components/schedules/ScheduleDetails.jsx
+++ b/packages/desktop-client/src/components/schedules/ScheduleDetails.jsx
@@ -18,6 +18,7 @@ import { theme } from '../../style';
 import { AccountAutocomplete } from '../autocomplete/AccountAutocomplete';
 import { PayeeAutocomplete } from '../autocomplete/PayeeAutocomplete';
 import { Button } from '../common/Button2';
+import { InitialFocus } from '../common/InitialFocus';
 import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2';
 import { Stack } from '../common/Stack';
 import { Text } from '../common/Text';
@@ -462,15 +463,17 @@ export function ScheduleDetails({ id, transaction }) {
           <Stack direction="row" style={{ marginTop: 10 }}>
             <FormField style={{ flex: 1 }}>
               <FormLabel title="Schedule Name" htmlFor="name-field" />
-              <GenericInput
-                field="string"
-                type="string"
-                value={state.fields.name}
-                multi={false}
-                onChange={e => {
-                  dispatch({ type: 'set-field', field: 'name', value: e });
-                }}
-              />
+              <InitialFocus>
+                <GenericInput
+                  field="string"
+                  type="string"
+                  value={state.fields.name}
+                  multi={false}
+                  onChange={e => {
+                    dispatch({ type: 'set-field', field: 'name', value: e });
+                  }}
+                />
+              </InitialFocus>
             </FormField>
           </Stack>
           <Stack direction="row" style={{ marginTop: 20 }}>
diff --git a/packages/desktop-client/src/components/schedules/ScheduleLink.tsx b/packages/desktop-client/src/components/schedules/ScheduleLink.tsx
index 74d22edd7..15b3409a7 100644
--- a/packages/desktop-client/src/components/schedules/ScheduleLink.tsx
+++ b/packages/desktop-client/src/components/schedules/ScheduleLink.tsx
@@ -13,6 +13,7 @@ import {
 
 import { SvgAdd } from '../../icons/v0';
 import { Button } from '../common/Button2';
+import { InitialFocus } from '../common/InitialFocus';
 import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2';
 import { Search } from '../common/Search';
 import { Text } from '../common/Text';
@@ -93,14 +94,16 @@ export function ScheduleLink({
                 : `this transaction belongs`}{' '}
               to:
             </Text>
-            <Search
-              inputRef={searchInput}
-              isInModal
-              width={300}
-              placeholder="Filter schedules…"
-              value={filter}
-              onChange={setFilter}
-            />
+            <InitialFocus>
+              <Search
+                inputRef={searchInput}
+                isInModal
+                width={300}
+                placeholder="Filter schedules…"
+                value={filter}
+                onChange={setFilter}
+              />
+            </InitialFocus>
             {ids.length === 1 && (
               <Button
                 variant="primary"
diff --git a/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx b/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx
index 20244423f..036b875c8 100644
--- a/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx
+++ b/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx
@@ -8,6 +8,7 @@ import { useDateFormat } from '../../hooks/useDateFormat';
 import { SvgAdd, SvgSubtract } from '../../icons/v0';
 import { theme } from '../../style';
 import { Button } from '../common/Button2';
+import { InitialFocus } from '../common/InitialFocus';
 import { Input } from '../common/Input';
 import { Menu } from '../common/Menu';
 import { Popover } from '../common/Popover';
@@ -310,14 +311,16 @@ function RecurringScheduleTooltip({ config: currentConfig, onClose, onSave }) {
     <>
       <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
         <label htmlFor="start">From</label>
-        <DateSelect
-          id="start"
-          inputProps={{ placeholder: 'Start Date' }}
-          value={config.start}
-          onSelect={value => updateField('start', value)}
-          containerProps={{ style: { width: 100 } }}
-          dateFormat={dateFormat}
-        />
+        <InitialFocus>
+          <DateSelect
+            id="start"
+            inputProps={{ placeholder: 'Start Date' }}
+            value={config.start}
+            onSelect={value => updateField('start', value)}
+            containerProps={{ style: { width: 100 } }}
+            dateFormat={dateFormat}
+          />
+        </InitialFocus>
         <Select
           id="repeat_end_dropdown"
           options={[
diff --git a/upcoming-release-notes/2974.md b/upcoming-release-notes/2974.md
new file mode 100644
index 000000000..ec6472220
--- /dev/null
+++ b/upcoming-release-notes/2974.md
@@ -0,0 +1,6 @@
+---
+category: Bugfix
+authors: [psybers]
+---
+
+Fix: Automatically focus inputs, or the primary button, in modals.
-- 
GitLab