Skip to content

Commit 9f8d0ce

Browse files
fix: tabindex and focus for footer component
1 parent 1ec047a commit 9f8d0ce

File tree

1 file changed

+28
-15
lines changed

1 file changed

+28
-15
lines changed

packages/template-retail-react-app/app/components/subscription/subscribe-form.jsx

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* SPDX-License-Identifier: BSD-3-Clause
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
7-
import React from 'react'
7+
import React, {useRef, useEffect} from 'react'
88
import PropTypes from 'prop-types'
99
import {
1010
Box,
@@ -27,6 +27,9 @@ const SubscribeForm = ({subscription, ...otherProps}) => {
2727
// Use SubscribeForm's own theme config instead of Footer's context
2828
const subscribeFormStyles = useMultiStyleConfig('SubscribeForm')
2929

30+
// Ref to manage focus on the email input
31+
const emailInputRef = useRef(null)
32+
3033
// Map SubscribeForm theme parts to Footer's expected structure
3134
const styles = {
3235
subscribe: subscribeFormStyles.container,
@@ -48,6 +51,19 @@ const SubscribeForm = ({subscription, ...otherProps}) => {
4851
const intl = useIntl()
4952
const {state, actions} = subscription
5053

54+
// Restore focus to the email input after submission completes (success or error)
55+
// Track previous loading state to detect when submission completes
56+
const prevLoadingRef = useRef(false)
57+
58+
useEffect(() => {
59+
// Only restore focus when transitioning from loading to not loading
60+
// This ensures we only focus after a submission completes, not on mount
61+
if (prevLoadingRef.current && !state?.isLoading && emailInputRef.current) {
62+
emailInputRef.current.focus()
63+
}
64+
prevLoadingRef.current = state?.isLoading
65+
}, [state?.isLoading])
66+
5167
const messages = {
5268
heading: intl.formatMessage({
5369
id: 'footer.subscribe.heading.stay_updated',
@@ -87,21 +103,8 @@ const SubscribeForm = ({subscription, ...otherProps}) => {
87103

88104
<Box>
89105
<InputGroup>
90-
{/* Had to swap the following InputRightElement and Input
91-
to avoid the hydration error due to mismatched html between server and client side.
92-
This is a workaround for Lastpass plugin that automatically injects its icon for input fields.
93-
*/}
94-
<InputRightElement {...styles.subscribeButtonContainer}>
95-
<Button
96-
variant="footer"
97-
onClick={actions?.submit}
98-
isLoading={state?.isLoading}
99-
loadingText={messages.buttonSignUp}
100-
>
101-
{messages.buttonSignUp}
102-
</Button>
103-
</InputRightElement>
104106
<Input
107+
ref={emailInputRef}
105108
type="email"
106109
placeholder={messages.emailPlaceholder}
107110
aria-label={messages.emailAriaLabel}
@@ -116,6 +119,16 @@ const SubscribeForm = ({subscription, ...otherProps}) => {
116119
id="subscribe-email"
117120
{...styles.subscribeField}
118121
/>
122+
<InputRightElement {...styles.subscribeButtonContainer}>
123+
<Button
124+
variant="footer"
125+
onClick={actions?.submit}
126+
isLoading={state?.isLoading}
127+
loadingText={messages.buttonSignUp}
128+
>
129+
{messages.buttonSignUp}
130+
</Button>
131+
</InputRightElement>
119132
</InputGroup>
120133

121134
<Text {...styles.subscribeDisclaimer}>

0 commit comments

Comments
 (0)