diff --git a/packages/@adobe/spectrum-css-temp/components/button/index.css b/packages/@adobe/spectrum-css-temp/components/button/index.css index 9b64d130917..559ac4c1842 100644 --- a/packages/@adobe/spectrum-css-temp/components/button/index.css +++ b/packages/@adobe/spectrum-css-temp/components/button/index.css @@ -167,7 +167,7 @@ governing permissions and limitations under the License. .spectrum-Button-label, .spectrum-Icon { - visibility: hidden; + opacity: 0; } } } diff --git a/packages/@react-spectrum/button/src/Button.tsx b/packages/@react-spectrum/button/src/Button.tsx index e55570b0477..d53dd47274a 100644 --- a/packages/@react-spectrum/button/src/Button.tsx +++ b/packages/@react-spectrum/button/src/Button.tsx @@ -22,6 +22,7 @@ import {FocusableRef} from '@react-types/shared'; import {FocusRing} from '@react-aria/focus'; // @ts-ignore import intlMessages from '../intl/*.json'; +import {isFirefox, isAppleDevice, isWebKit} from '@react-aria/utils/src/platform'; import {mergeProps, useId} from '@react-aria/utils'; import {ProgressCircle} from '@react-spectrum/progress'; import React, {ElementType, ReactElement, useEffect, useState} from 'react'; @@ -78,10 +79,9 @@ function Button(props: SpectrumButtonProps, let [isProgressVisible, setIsProgressVisible] = useState(false); let backupButtonId = useId(); let buttonId = buttonProps.id || backupButtonId; - let spinnerId = useId(); - let textId = useId(); let iconId = useId(); - let auxLabelId = useId(); + let textId = useId(); + let spinnerId = useId(); useEffect(() => { let timeout: ReturnType; @@ -108,6 +108,13 @@ function Button(props: SpectrumButtonProps, staticColor = 'white'; } + const isPendingAriaLiveLabel = `${hasAriaLabel ? buttonProps['aria-label'] : ''} ${stringFormatter.format('pending')}`.trim(); + const isPendingAriaLiveLabelledby = hasAriaLabel ? (buttonProps['aria-labelledby']?.replace(buttonId, spinnerId) ?? spinnerId) : `${hasIcon ? iconId : ''} ${hasLabel ? textId : ''} ${spinnerId}`.trim(); + + let ariaLive: 'off' | 'polite' | 'assertive' = 'polite'; + if (isAppleDevice() && (!hasAriaLabel || isFirefox())) { + ariaLive = 'off'; + } return ( (props: SpectrumButtonProps, data-style={style} data-static-color={staticColor || undefined} aria-disabled={isPending ? 'true' : undefined} - aria-label={isPending ? undefined : buttonProps['aria-label']} - aria-labelledby={isPending ? undefined : buttonProps['aria-labelledby']} - aria-live={isPending && isFocused ? 'polite' : undefined} + aria-label={isPending ? isPendingAriaLiveLabel : buttonProps['aria-label']} + aria-labelledby={isPending ? isPendingAriaLiveLabelledby : buttonProps['aria-labelledby']} className={ classNames( styles, @@ -153,23 +159,26 @@ function Button(props: SpectrumButtonProps, : children} {isPending &&