diff --git a/src/components/ActivityIndicator.tsx b/src/components/ActivityIndicator.tsx
index 9436979208..5b1d8ff77e 100644
--- a/src/components/ActivityIndicator.tsx
+++ b/src/components/ActivityIndicator.tsx
@@ -146,8 +146,8 @@ const ActivityIndicator = ({
style={[styles.container, style]}
{...rest}
accessible
- accessibilityRole="progressbar"
- accessibilityState={{ busy: animating }}
+ role="progressbar"
+ aria-busy={animating}
>
& {
/**
* Accessibility label for the button. This is read by the screen reader when the user taps the button.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Function to execute on press.
*/
@@ -79,7 +79,7 @@ const AppbarAction = ({
icon,
disabled,
onPress,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
isLeading,
theme: themeOverrides,
ref,
@@ -101,7 +101,7 @@ const AppbarAction = ({
iconColor={actionIconColor}
icon={icon}
disabled={disabled}
- accessibilityLabel={accessibilityLabel}
+ aria-label={ariaLabel}
animated
ref={ref}
{...rest}
diff --git a/src/components/Appbar/AppbarBackAction.tsx b/src/components/Appbar/AppbarBackAction.tsx
index 80c7df2f95..2835c27c91 100644
--- a/src/components/Appbar/AppbarBackAction.tsx
+++ b/src/components/Appbar/AppbarBackAction.tsx
@@ -31,7 +31,7 @@ export type Props = $Omit<
/**
* Accessibility label for the button. This is read by the screen reader when the user taps the button.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Function to execute on press.
*/
@@ -58,12 +58,12 @@ export type Props = $Omit<
* ```
*/
const AppbarBackAction = ({
- accessibilityLabel = 'Back',
+ 'aria-label': ariaLabel = 'Back',
ref,
...rest
}: Props) => (
@@ -164,11 +155,8 @@ const AppbarContent = ({
return (
// eslint-disable-next-line react-native-a11y/has-accessibility-props
{children}
diff --git a/src/components/BottomNavigation/BottomNavigation.tsx b/src/components/BottomNavigation/BottomNavigation.tsx
index 1f18b17aae..29fab333d3 100644
--- a/src/components/BottomNavigation/BottomNavigation.tsx
+++ b/src/components/BottomNavigation/BottomNavigation.tsx
@@ -523,7 +523,7 @@ const BottomNavigation = ({
({
),
getLabelText = ({ route }: { route: Route }) => route.title,
getBadge = ({ route }: { route: Route }) => route.badge,
- getAccessibilityLabel = ({ route }: { route: Route }) =>
- route.accessibilityLabel,
+ getAccessibilityLabel = ({ route }: { route: Route }) => route['aria-label'],
getTestID = ({ route }: { route: Route }) => route.testID,
activeColor,
inactiveColor,
@@ -507,7 +509,7 @@ const BottomNavigationBar = ({
maxWidth: maxTabBarWidth,
},
]}
- accessibilityRole={'tablist'}
+ role={'tablist'}
testID={`${testID}-content-wrapper`}
>
{routes.map((route, index) => {
@@ -585,9 +587,9 @@ const BottomNavigationBar = ({
onPress: () => onTabPress(eventForIndex(index)),
onLongPress: () => onTabLongPress?.(eventForIndex(index)),
testID: getTestID({ route }),
- accessibilityLabel: getAccessibilityLabel({ route }),
- accessibilityRole: Platform.OS === 'ios' ? 'button' : 'tab',
- accessibilityState: { selected: focused },
+ 'aria-label': getAccessibilityLabel({ route }),
+ role: Platform.OS === 'ios' ? 'button' : 'tab',
+ 'aria-selected': focused,
style: [styles.item, styles.v3Item],
children: (
, 'mode'> & {
/**
* Accessibility label for the button. This is read by the screen reader when the user taps the button.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Accessibility hint for the button. This is read by the screen reader when the user taps the button.
*/
@@ -88,7 +87,7 @@ export type Props = $Omit, 'mode'> & {
/**
* Accessibility role for the button. The "button" role is set by default.
*/
- accessibilityRole?: AccessibilityRole;
+ role?: string;
/**
* Function to execute on press.
*/
@@ -169,9 +168,9 @@ const Button = ({
buttonColor: customButtonColor,
textColor: customTextColor,
children,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
accessibilityHint,
- accessibilityRole = 'button',
+ role = 'button',
hitSlop,
onPress,
onPressIn,
@@ -352,10 +351,10 @@ const Button = ({
onPressIn={hasPassedTouchHandler ? handlePressIn : undefined}
onPressOut={hasPassedTouchHandler ? handlePressOut : undefined}
delayLongPress={delayLongPress}
- accessibilityLabel={accessibilityLabel}
+ aria-label={ariaLabel}
accessibilityHint={accessibilityHint}
- accessibilityRole={accessibilityRole}
- accessibilityState={{ disabled }}
+ role={role}
+ aria-disabled={disabled}
accessible={accessible}
hitSlop={hitSlop}
disabled={disabled}
diff --git a/src/components/Checkbox/Checkbox.tsx b/src/components/Checkbox/Checkbox.tsx
index 7173e64501..021c3af904 100644
--- a/src/components/Checkbox/Checkbox.tsx
+++ b/src/components/Checkbox/Checkbox.tsx
@@ -247,14 +247,12 @@ const Checkbox = ({
rest.accessible === false
? {}
: {
- accessibilityRole: 'checkbox' as const,
- accessibilityState: {
- disabled: !!disabled,
- checked: (status === 'indeterminate'
- ? 'mixed'
- : status === 'checked') as boolean | 'mixed',
- },
- accessibilityLiveRegion: 'polite' as const,
+ role: 'checkbox' as const,
+ 'aria-disabled': !!disabled,
+ 'aria-checked': (status === 'indeterminate'
+ ? 'mixed'
+ : status === 'checked') as boolean | 'mixed',
+ 'aria-live': 'polite' as const,
};
return (
diff --git a/src/components/Checkbox/CheckboxItem.tsx b/src/components/Checkbox/CheckboxItem.tsx
index 50e758a412..e8bd23a59b 100644
--- a/src/components/Checkbox/CheckboxItem.tsx
+++ b/src/components/Checkbox/CheckboxItem.tsx
@@ -44,7 +44,7 @@ export type Props = {
/**
* Accessibility label for the touchable. This is read by the screen reader when the user taps the touchable.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Custom color for unchecked checkbox.
*/
@@ -129,7 +129,7 @@ const CheckboxItem = ({
theme: themeOverrides,
testID,
position = 'trailing',
- accessibilityLabel = label,
+ 'aria-label': ariaLabel = label,
disabled,
labelVariant = 'bodyLarge',
labelMaxFontSizeMultiplier = 1.5,
@@ -154,12 +154,10 @@ const CheckboxItem = ({
return (
, 'mode'> & {
/**
* Accessibility label for the chip. This is read by the screen reader when the user taps the chip.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Accessibility label for the close icon. This is read by the screen reader when the user taps the close icon.
*/
@@ -178,8 +177,8 @@ const Chip = ({
selected = false,
disabled = false,
background,
- accessibilityLabel,
- accessibilityRole = 'button',
+ 'aria-label': ariaLabel,
+ role = 'button',
closeIconAccessibilityLabel = 'Close',
onPress,
onLongPress,
@@ -263,11 +262,6 @@ const Chip = ({
disabled,
});
- const accessibilityState: AccessibilityState = {
- selected,
- disabled,
- };
-
const elevationStyle = elevation;
const multiplier = compact ? 1.5 : 2;
const labelSpacings = {
@@ -312,9 +306,10 @@ const Chip = ({
onPressOut={hasPassedTouchHandler ? handlePressOut : undefined}
delayLongPress={delayLongPress}
disabled={disabled}
- accessibilityLabel={accessibilityLabel}
- accessibilityRole={accessibilityRole}
- accessibilityState={accessibilityState}
+ aria-label={ariaLabel}
+ role={role}
+ aria-selected={selected}
+ aria-disabled={disabled}
testID={testID}
theme={theme}
hitSlop={hitSlop}
@@ -401,8 +396,8 @@ const Chip = ({
{closeIcon ? (
diff --git a/src/components/DataTable/DataTablePagination.tsx b/src/components/DataTable/DataTablePagination.tsx
index 862185e9c5..32f4b8b4fb 100644
--- a/src/components/DataTable/DataTablePagination.tsx
+++ b/src/components/DataTable/DataTablePagination.tsx
@@ -29,7 +29,7 @@ export type Props = ViewProps &
/**
* AccessibilityLabel for `label`.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
style?: StyleProp;
/**
* @optional
@@ -106,7 +106,7 @@ const PaginationControls = ({
iconColor={textColor}
disabled={page === 0}
onPress={() => onPageChange(0)}
- accessibilityLabel="page-first"
+ aria-label="page-first"
theme={theme}
/>
) : null}
@@ -122,7 +122,7 @@ const PaginationControls = ({
iconColor={textColor}
disabled={page === 0}
onPress={() => onPageChange(page - 1)}
- accessibilityLabel="chevron-left"
+ aria-label="chevron-left"
theme={theme}
/>
onPageChange(page + 1)}
- accessibilityLabel="chevron-right"
+ aria-label="chevron-right"
theme={theme}
/>
{showFastPaginationControls ? (
@@ -153,7 +153,7 @@ const PaginationControls = ({
iconColor={textColor}
disabled={numberOfPages === 0 || page === numberOfPages - 1}
onPress={() => onPageChange(numberOfPages - 1)}
- accessibilityLabel="page-last"
+ aria-label="page-last"
theme={theme}
/>
) : null}
@@ -266,7 +266,7 @@ const PaginationDropdown = ({
*/
const DataTablePagination = ({
label,
- accessibilityLabel,
+ 'aria-label': accessibilityLabel,
page,
numberOfPages,
onPageChange,
@@ -287,19 +287,21 @@ const DataTablePagination = ({
{numberOfItemsPerPageList &&
numberOfItemsPerPage &&
onItemsPerPageChange && (
{label}
diff --git a/src/components/Dialog/DialogTitle.tsx b/src/components/Dialog/DialogTitle.tsx
index f869887205..bdf5021379 100644
--- a/src/components/Dialog/DialogTitle.tsx
+++ b/src/components/Dialog/DialogTitle.tsx
@@ -63,7 +63,7 @@ const DialogTitle = ({
return (
diff --git a/src/components/Drawer/DrawerCollapsedItem.tsx b/src/components/Drawer/DrawerCollapsedItem.tsx
index 3f79fce421..66346e92bb 100644
--- a/src/components/Drawer/DrawerCollapsedItem.tsx
+++ b/src/components/Drawer/DrawerCollapsedItem.tsx
@@ -54,7 +54,7 @@ export type Props = ViewProps & {
/**
* Accessibility label for the button. This is read by the screen reader when the user taps the button.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
style?: StyleProp;
/**
* @optional
@@ -102,7 +102,7 @@ const DrawerCollapsedItem = ({
style,
onPress,
disabled,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
badge = false,
testID = 'drawer-collapsed-item',
labelMaxFontSizeMultiplier,
@@ -169,12 +169,9 @@ const DrawerCollapsedItem = ({
onPress={onPress}
onPressOut={onPress ? handlePressOut : undefined}
disabled={disabled}
- // @ts-expect-error We keep old a11y props for backwards compat with old RN versions
- accessibilityTraits={active ? ['button', 'selected'] : 'button'}
- accessibilityComponentType="button"
- accessibilityRole="button"
- accessibilityState={{ selected: active }}
- accessibilityLabel={accessibilityLabel}
+ role="button"
+ aria-selected={active}
+ aria-label={ariaLabel}
testID={testID}
>
diff --git a/src/components/Drawer/DrawerItem.tsx b/src/components/Drawer/DrawerItem.tsx
index 95ef989248..88535ba162 100644
--- a/src/components/Drawer/DrawerItem.tsx
+++ b/src/components/Drawer/DrawerItem.tsx
@@ -46,7 +46,7 @@ export type Props = ViewProps & {
/**
* Accessibility label for the button. This is read by the screen reader when the user taps the button.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Callback which returns a React element to display on the right side. For instance a Badge.
*/
@@ -94,7 +94,7 @@ const DrawerItem = ({
style,
onPress,
background,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
right,
labelMaxFontSizeMultiplier,
hitSlop,
@@ -124,9 +124,9 @@ const DrawerItem = ({
{ backgroundColor, borderRadius },
style,
]}
- accessibilityRole="button"
- accessibilityState={{ selected: active }}
- accessibilityLabel={accessibilityLabel}
+ role="button"
+ aria-selected={active}
+ aria-label={ariaLabel}
theme={theme}
hitSlop={hitSlop}
>
diff --git a/src/components/FAB/Extended.tsx b/src/components/FAB/Extended.tsx
index d15fe6a6fa..06a67cab1f 100644
--- a/src/components/FAB/Extended.tsx
+++ b/src/components/FAB/Extended.tsx
@@ -1,7 +1,6 @@
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import type {
- AccessibilityState,
ColorValue,
GestureResponderEvent,
PressableAndroidRippleConfig,
@@ -71,11 +70,24 @@ export type Props = {
/**
* Accessibility label. Falls back to `label` if unset.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
- * Accessibility state forwarded to the underlying button.
+ * Indicates whether the element is checked. Accepts `true`, `false`,
+ * or `'mixed'` for an indeterminate state.
*/
- accessibilityState?: AccessibilityState;
+ 'aria-checked'?: boolean | 'mixed';
+ /**
+ * Indicates whether the element is selected.
+ */
+ 'aria-selected'?: boolean;
+ /**
+ * Indicates whether the element is currently busy (e.g. loading).
+ */
+ 'aria-busy'?: boolean;
+ /**
+ * Indicates whether the element's controlled content is expanded.
+ */
+ 'aria-expanded'?: boolean;
/**
* Specifies the largest possible scale a label font can reach.
*/
@@ -148,8 +160,11 @@ const Extended = ({
expanded,
visible = true,
onPress,
- accessibilityLabel = label,
- accessibilityState,
+ 'aria-label': ariaLabel = label,
+ 'aria-checked': ariaChecked,
+ 'aria-selected': ariaSelected,
+ 'aria-busy': ariaBusy,
+ 'aria-expanded': ariaExpanded,
labelMaxFontSizeMultiplier,
background,
style,
@@ -239,8 +254,11 @@ const Extended = ({
size={size}
visible={visible}
onPress={onPress}
- accessibilityLabel={accessibilityLabel}
- accessibilityState={accessibilityState}
+ aria-label={ariaLabel}
+ aria-checked={ariaChecked}
+ aria-selected={ariaSelected}
+ aria-busy={ariaBusy}
+ aria-expanded={ariaExpanded}
background={background}
widthShared={widthValue}
labelMaxFontSizeMultiplier={labelMaxFontSizeMultiplier}
@@ -253,7 +271,7 @@ const Extended = ({
ref={offscreenLabelRef}
style={styles.offscreenMeasure}
importantForAccessibility="no-hide-descendants"
- accessibilityElementsHidden
+ aria-hidden
>
void;
- accessibilityLabel?: string;
+ /**
+ * Accessibility label for the trigger FAB.
+ */
+ 'aria-label'?: string;
testID?: string;
};
@@ -206,7 +209,7 @@ const AnimatedItem = ({
expanded ? styles.pointerEventsAuto : styles.pointerEventsNone,
]}
importantForAccessibility={expanded ? 'yes' : 'no-hide-descendants'}
- accessibilityElementsHidden={!expanded}
+ aria-hidden={!expanded}
>
{children}
@@ -219,7 +222,10 @@ type ItemProps = {
variant: Variant;
theme: InternalTheme;
onPress: (e: GestureResponderEvent) => void;
- accessibilityLabel?: string;
+ /**
+ * Accessibility label. Falls back to `label`.
+ */
+ 'aria-label'?: string;
testID?: string;
};
@@ -235,7 +241,7 @@ const MenuItem = ({
variant,
theme,
onPress,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
testID,
}: ItemProps) => {
const colors = resolveColors({ theme, variant });
@@ -261,8 +267,8 @@ const MenuItem = ({
onPress={onPress}
onFocus={onFocus}
onBlur={onBlur}
- accessibilityRole="button"
- accessibilityLabel={accessibilityLabel ?? label}
+ role="button"
+ aria-label={ariaLabel ?? label}
style={[
{ borderRadius },
Platform.OS === 'web' ? webNoOutline : null,
@@ -309,7 +315,10 @@ type MorphingTriggerProps = {
visible: boolean;
alignment: 'start' | 'center' | 'end';
onPress?: (e: GestureResponderEvent) => void;
- accessibilityLabel?: string;
+ /**
+ * Accessibility label for the trigger button.
+ */
+ 'aria-label'?: string;
theme: InternalTheme;
testID?: string;
};
@@ -326,7 +335,7 @@ const MorphingTrigger = ({
visible,
alignment,
onPress,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
theme,
testID,
}: MorphingTriggerProps) => {
@@ -446,7 +455,7 @@ const MorphingTrigger = ({
contentColor={triggerContentColor}
visible={visible}
onPress={onPress}
- accessibilityLabel={accessibilityLabel}
+ aria-label={ariaLabel}
widthShared={widthShared}
heightShared={heightShared}
borderRadiusShared={borderRadiusShared}
@@ -616,7 +625,7 @@ const Menu = ({
label={item.label}
variant={itemsVariant}
theme={theme}
- accessibilityLabel={item.accessibilityLabel ?? item.label}
+ aria-label={item['aria-label'] ?? item.label}
onPress={handleItemPress(item)}
testID={item.testID}
/>
@@ -636,7 +645,7 @@ const Menu = ({
visible={triggerVisible}
alignment={alignment}
onPress={effectiveExpanded ? onDismiss : openOnPress}
- accessibilityLabel={trigger.accessibilityLabel}
+ aria-label={trigger['aria-label']}
theme={theme}
testID={trigger.testID}
/>
diff --git a/src/components/FAB/Shell.tsx b/src/components/FAB/Shell.tsx
index 4f9b9b5da9..2d2d60e4cd 100644
--- a/src/components/FAB/Shell.tsx
+++ b/src/components/FAB/Shell.tsx
@@ -1,7 +1,6 @@
import * as React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import type {
- AccessibilityState,
ColorValue,
GestureResponderEvent,
PressableAndroidRippleConfig,
@@ -92,11 +91,24 @@ export type ShellProps = {
/**
* Accessibility label. Falls back to `label` if unset.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
- * Accessibility state forwarded to the underlying button.
+ * Indicates whether the element is checked. Accepts `true`, `false`,
+ * or `'mixed'` for an indeterminate state.
*/
- accessibilityState?: AccessibilityState;
+ 'aria-checked'?: boolean | 'mixed';
+ /**
+ * Indicates whether the element is selected.
+ */
+ 'aria-selected'?: boolean;
+ /**
+ * Indicates whether the element is currently busy (e.g. loading).
+ */
+ 'aria-busy'?: boolean;
+ /**
+ * Indicates whether the element's controlled content is expanded.
+ */
+ 'aria-expanded'?: boolean;
/**
* Largest scale the label font can reach (auto-built content only).
*/
@@ -182,8 +194,11 @@ const Shell = ({
elevation = Tokens.stateElevation.enabled,
visible = true,
onPress,
- accessibilityLabel = label,
- accessibilityState,
+ 'aria-label': ariaLabel = label,
+ 'aria-checked': ariaChecked,
+ 'aria-selected': ariaSelected,
+ 'aria-busy': ariaBusy,
+ 'aria-expanded': ariaExpanded,
labelMaxFontSizeMultiplier,
labelAnimatedStyle,
background,
@@ -290,9 +305,12 @@ const Shell = ({
onPress={onPress}
onFocus={onFocus}
onBlur={onBlur}
- accessibilityLabel={accessibilityLabel}
- accessibilityRole="button"
- accessibilityState={accessibilityState}
+ aria-label={ariaLabel}
+ role="button"
+ aria-checked={ariaChecked}
+ aria-selected={ariaSelected}
+ aria-busy={ariaBusy}
+ aria-expanded={ariaExpanded}
testID={testID}
style={[
children ? styles.fill : null,
diff --git a/src/components/IconButton/IconButton.tsx b/src/components/IconButton/IconButton.tsx
index 899d1e5a46..52a64e98d0 100644
--- a/src/components/IconButton/IconButton.tsx
+++ b/src/components/IconButton/IconButton.tsx
@@ -59,7 +59,7 @@ export type Props = Omit<$RemoveChildren, 'style'> & {
/**
* Accessibility label for the button. This is read by the screen reader when the user taps the button.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Style of button's inner content.
* Use this prop to apply custom height and width or to set a custom padding`.
@@ -112,7 +112,7 @@ const IconButton = ({
iconColor: customIconColor,
containerColor: customContainerColor,
size = 24,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
disabled,
onPress,
selected = false,
@@ -188,13 +188,10 @@ const IconButton = ({
borderless
centered
onPress={onPress}
- accessibilityLabel={accessibilityLabel}
+ aria-label={ariaLabel}
style={[styles.touchable, contentStyle]}
- // @ts-expect-error We keep old a11y props for backwards compat with old RN versions
- accessibilityTraits={disabled ? ['button', 'disabled'] : 'button'}
- accessibilityComponentType="button"
- accessibilityRole="button"
- accessibilityState={{ disabled }}
+ role="button"
+ aria-disabled={disabled}
disabled={disabled}
hitSlop={
TouchableRipple.supported
diff --git a/src/components/List/ListAccordion.tsx b/src/components/List/ListAccordion.tsx
index 5dbca2ee60..97730d58e6 100644
--- a/src/components/List/ListAccordion.tsx
+++ b/src/components/List/ListAccordion.tsx
@@ -120,7 +120,7 @@ export type Props = {
/**
* Accessibility label for the TouchableRipple. This is read by the screen reader when the user taps the touchable.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* `pointerEvents` passed to the `View` container
*/
@@ -190,7 +190,7 @@ const ListAccordion = ({
onLongPress,
delayLongPress,
expanded: expandedProp,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
pointerEvents = 'none',
titleMaxFontSizeMultiplier,
descriptionMaxFontSizeMultiplier,
@@ -249,9 +249,9 @@ const ListAccordion = ({
onPress={handlePress}
onLongPress={onLongPress}
delayLongPress={delayLongPress}
- accessibilityRole="button"
- accessibilityState={{ expanded: isExpanded }}
- accessibilityLabel={accessibilityLabel}
+ role="button"
+ aria-expanded={isExpanded}
+ aria-label={ariaLabel}
testID={testID}
theme={theme}
background={background}
diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx
index 4c3d6fe65e..97fc7748cd 100644
--- a/src/components/Menu/Menu.tsx
+++ b/src/components/Menu/Menu.tsx
@@ -642,8 +642,8 @@ const Menu = ({
{rendered ? (
diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx
index a8412da806..3c66c885b3 100644
--- a/src/components/Modal.tsx
+++ b/src/components/Modal.tsx
@@ -182,15 +182,15 @@ function Modal({
return (
diff --git a/src/components/RadioButton/RadioButtonAndroid.tsx b/src/components/RadioButton/RadioButtonAndroid.tsx
index a907b46b09..5fcaf9f6e5 100644
--- a/src/components/RadioButton/RadioButtonAndroid.tsx
+++ b/src/components/RadioButton/RadioButtonAndroid.tsx
@@ -134,9 +134,10 @@ const RadioButtonAndroid = ({
});
}
}
- accessibilityRole="radio"
- accessibilityState={{ disabled, checked }}
- accessibilityLiveRegion="polite"
+ role="radio"
+ aria-disabled={disabled}
+ aria-checked={checked}
+ aria-live="polite"
style={styles.container}
testID={testID}
theme={theme}
diff --git a/src/components/RadioButton/RadioButtonGroup.tsx b/src/components/RadioButton/RadioButtonGroup.tsx
index 2bdd596561..8522bf3fc4 100644
--- a/src/components/RadioButton/RadioButtonGroup.tsx
+++ b/src/components/RadioButton/RadioButtonGroup.tsx
@@ -56,7 +56,7 @@ export const RadioButtonContext = React.createContext(
*/
const RadioButtonGroup = ({ value, onValueChange, children }: Props) => (
- {children}
+ {children}
);
diff --git a/src/components/RadioButton/RadioButtonIOS.tsx b/src/components/RadioButton/RadioButtonIOS.tsx
index e2e5f06c7c..015356eea3 100644
--- a/src/components/RadioButton/RadioButtonIOS.tsx
+++ b/src/components/RadioButton/RadioButtonIOS.tsx
@@ -92,9 +92,10 @@ const RadioButtonIOS = ({
});
}
}
- accessibilityRole="radio"
- accessibilityState={{ disabled, checked }}
- accessibilityLiveRegion="polite"
+ role="radio"
+ aria-disabled={disabled}
+ aria-checked={checked}
+ aria-live="polite"
style={styles.container}
testID={testID}
theme={theme}
diff --git a/src/components/RadioButton/RadioButtonItem.tsx b/src/components/RadioButton/RadioButtonItem.tsx
index 1591760980..e37ed435e2 100644
--- a/src/components/RadioButton/RadioButtonItem.tsx
+++ b/src/components/RadioButton/RadioButtonItem.tsx
@@ -49,7 +49,7 @@ export type Props = {
/**
* Accessibility label for the touchable. This is read by the screen reader when the user taps the touchable.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Custom color for unchecked radio.
*/
@@ -149,7 +149,7 @@ const RadioButtonItem = ({
status,
theme: themeOverrides,
background,
- accessibilityLabel = label,
+ 'aria-label': ariaLabel = label,
testID,
mode,
position = 'trailing',
@@ -204,12 +204,10 @@ const RadioButtonItem = ({
})
}
onLongPress={onLongPress}
- accessibilityLabel={accessibilityLabel}
- accessibilityRole="radio"
- accessibilityState={{
- checked,
- disabled,
- }}
+ aria-label={ariaLabel}
+ role="radio"
+ aria-checked={checked}
+ aria-disabled={disabled}
testID={testID}
disabled={disabled}
background={background}
diff --git a/src/components/Searchbar.tsx b/src/components/Searchbar.tsx
index a081b62fc4..3cc733e126 100644
--- a/src/components/Searchbar.tsx
+++ b/src/components/Searchbar.tsx
@@ -245,7 +245,7 @@ const Searchbar = ({
theme={theme}
>
)}
{shouldRenderTraileringIcon ? (
) : null}
diff --git a/src/components/SegmentedButtons/SegmentedButtonItem.tsx b/src/components/SegmentedButtons/SegmentedButtonItem.tsx
index 0d30d8aee4..4f701f0b48 100644
--- a/src/components/SegmentedButtons/SegmentedButtonItem.tsx
+++ b/src/components/SegmentedButtons/SegmentedButtonItem.tsx
@@ -52,7 +52,7 @@ export type Props = {
/**
* Accessibility label for the `SegmentedButtonItem`. This is read by the screen reader when the user taps the button.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Function to execute on press.
*/
@@ -102,7 +102,7 @@ export type Props = {
const SegmentedButtonItem = ({
checked,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
disabled,
style,
labelStyle,
@@ -195,9 +195,10 @@ const SegmentedButtonItem = ({
diff --git a/src/components/Switch/Switch.tsx b/src/components/Switch/Switch.tsx
index 1eb0c23de6..0bcc53083b 100644
--- a/src/components/Switch/Switch.tsx
+++ b/src/components/Switch/Switch.tsx
@@ -57,7 +57,10 @@ export type Props = {
style?: StyleProp;
testID?: string;
theme?: ThemeProp;
- accessibilityLabel?: string;
+ /**
+ * Accessibility label for the switch. This is read by the screen reader when the user focuses the switch.
+ */
+ 'aria-label'?: string;
};
const {
@@ -132,7 +135,7 @@ const Switch = ({
style,
testID,
theme: themeOverrides,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
}: Props) => {
const theme = useInternalTheme(themeOverrides);
const reduceMotion = useReduceMotion();
@@ -367,9 +370,10 @@ const Switch = ({
focusedSV.value = 0;
}}
android_ripple={{ color: 'transparent' }}
- accessibilityRole="switch"
- accessibilityState={{ disabled: isDisabled, checked }}
- accessibilityLabel={accessibilityLabel}
+ role="switch"
+ aria-disabled={isDisabled}
+ aria-checked={checked}
+ aria-label={ariaLabel}
testID={testID}
style={[
styles.touchable,
diff --git a/src/components/TextInput/TextInput.tsx b/src/components/TextInput/TextInput.tsx
index 806dd4585a..5a7a65d974 100644
--- a/src/components/TextInput/TextInput.tsx
+++ b/src/components/TextInput/TextInput.tsx
@@ -57,7 +57,7 @@ export type TextInputColors = {
};
export type GetAccessibilityDataReturn = {
- input: AccessibilityProps;
+ input: AccessibilityProps & { 'aria-invalid'?: boolean };
supportingText: AccessibilityProps;
counter: AccessibilityProps;
};
diff --git a/src/components/TextInput/utils.ts b/src/components/TextInput/utils.ts
index e8da1a4de3..ad81f55301 100644
--- a/src/components/TextInput/utils.ts
+++ b/src/components/TextInput/utils.ts
@@ -611,19 +611,14 @@ export const getAccessibilityData = ({
: `Characters entered ${inputLength} of ${maxLength}`
: undefined;
- const accessibilityState = {
- disabled: isDisabled,
- invalid: isInvalid,
- ...props.accessibilityState,
- } as const;
-
return {
input: {
'aria-label': ariaLabel,
'aria-valuemax': isCounterReached ? maxLength : undefined,
'aria-valuenow': isCounterReached ? inputLength : undefined,
+ 'aria-disabled': isDisabled,
+ 'aria-invalid': isInvalid,
accessibilityHint: hint,
- accessibilityState,
},
supportingText: {
'aria-hidden': isSupportingTextHidden,
diff --git a/src/components/ToggleButton/ToggleButton.tsx b/src/components/ToggleButton/ToggleButton.tsx
index 8d4cdd556f..22598c16b2 100644
--- a/src/components/ToggleButton/ToggleButton.tsx
+++ b/src/components/ToggleButton/ToggleButton.tsx
@@ -29,7 +29,7 @@ export type Props = {
/**
* Accessibility label for the `ToggleButton`. This is read by the screen reader when the user taps the button.
*/
- accessibilityLabel?: string;
+ 'aria-label'?: string;
/**
* Function to execute on press.
*/
@@ -88,7 +88,7 @@ const ToggleButton = ({
icon,
size,
theme: themeOverrides,
- accessibilityLabel,
+ 'aria-label': ariaLabel,
disabled,
style,
value,
@@ -123,8 +123,9 @@ const ToggleButton = ({
}
}}
size={size}
- accessibilityLabel={accessibilityLabel}
- accessibilityState={{ disabled, selected: checked }}
+ aria-label={ariaLabel}
+ aria-disabled={disabled}
+ aria-selected={checked}
disabled={disabled}
style={[
styles.content,
diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx
index 36dc08971b..8d237d6991 100644
--- a/src/components/Tooltip/Tooltip.tsx
+++ b/src/components/Tooltip/Tooltip.tsx
@@ -215,7 +215,7 @@ const Tooltip = ({
testID="tooltip-container"
>
{
);
});
- it('Is recognized as a header when no onPress callback has been pressed', () => {
- const { getByRole } = render(
+ it('Is recognized as a heading when no onPress callback has been passed', () => {
+ const { getByTestId } = render(
@@ -155,7 +155,7 @@ describe('renderAppbarContent', () => {
);
- expect(getByRole('header')).toBeTruthy();
+ expect(getByTestId('appbar-content-title-text').props.role).toBe('heading');
});
it('is recognized as a button when onPress callback has been passed', () => {
const { getByTestId } = render(
@@ -166,15 +166,11 @@ describe('renderAppbarContent', () => {
);
- expect(getByTestId('appbar-content').props.accessibilityRole).toEqual(
- 'button'
- );
+ expect(getByTestId('appbar-content').props.role).toEqual('button');
expect(
getByTestId('appbar-content').props.accessibilityState || {}
).not.toMatchObject({ disabled: true });
- expect(
- getByTestId('appbar-content-title-text').props.accessibilityRole
- ).toEqual('none');
+ expect(getByTestId('appbar-content-title-text').props.role).toEqual('none');
});
it('is recognized as a disabled button when onPress and disabled is passed', () => {
const { getByTestId } = render(
@@ -185,15 +181,11 @@ describe('renderAppbarContent', () => {
);
- expect(getByTestId('appbar-content').props.accessibilityRole).toEqual(
- 'button'
- );
+ expect(getByTestId('appbar-content').props.role).toEqual('button');
expect(
getByTestId('appbar-content').props.accessibilityState
).toMatchObject({ disabled: true });
- expect(
- getByTestId('appbar-content-title-text').props.accessibilityRole
- ).toEqual('none');
+ expect(getByTestId('appbar-content-title-text').props.role).toEqual('none');
});
});
diff --git a/src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap b/src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap
index 7dbcf9f0a5..a5d9d95766 100644
--- a/src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap
+++ b/src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap
@@ -122,9 +122,7 @@ exports[`Appbar does not pass any additional props to Searchbar 1`] = `
testID="search-bar-icon-container"
>
{
);
diff --git a/src/components/__tests__/Checkbox/__snapshots__/Checkbox.test.tsx.snap b/src/components/__tests__/Checkbox/__snapshots__/Checkbox.test.tsx.snap
index 1b21c11b68..54f2e4f7a4 100644
--- a/src/components/__tests__/Checkbox/__snapshots__/Checkbox.test.tsx.snap
+++ b/src/components/__tests__/Checkbox/__snapshots__/Checkbox.test.tsx.snap
@@ -3,7 +3,6 @@
exports[`renders Checkbox with custom testID 1`] = `
{
});
it('renders data table pagination without options select', () => {
- const { queryByLabelText } = render(
+ const { queryByTestId } = render(
{
/>
);
- expect(queryByLabelText('Options Select')).toBeFalsy();
+ expect(queryByTestId('options-select')).toBeFalsy();
});
it('renders data table pagination with options select', () => {
- const { getByLabelText, toJSON } = render(
+ const { getByTestId, toJSON } = render(
{
/>
);
- expect(getByLabelText('Options Select')).toBeTruthy();
- expect(getByLabelText('selectPageDropdownLabel')).toBeTruthy();
+ expect(getByTestId('options-select').props['aria-label']).toBe(
+ 'Options Select'
+ );
+ expect(getByTestId('select-page-dropdown-label').props['aria-label']).toBe(
+ 'selectPageDropdownLabel'
+ );
expect(toJSON()).toMatchSnapshot();
});
diff --git a/src/components/__tests__/FAB.test.tsx b/src/components/__tests__/FAB.test.tsx
index 38ee6308b6..65e2f6418a 100644
--- a/src/components/__tests__/FAB.test.tsx
+++ b/src/components/__tests__/FAB.test.tsx
@@ -56,10 +56,8 @@ it('renders FAB with containerColor and contentColor overrides', () => {
expect(tree).toMatchSnapshot();
});
-it('renders FAB with accessibilityLabel', () => {
- const tree = render(
-
- ).toJSON();
+it('renders FAB with aria-label', () => {
+ const tree = render().toJSON();
expect(tree).toMatchSnapshot();
});
diff --git a/src/components/__tests__/FABExtended.test.tsx b/src/components/__tests__/FABExtended.test.tsx
index e3c1490f65..689b25eb8f 100644
--- a/src/components/__tests__/FABExtended.test.tsx
+++ b/src/components/__tests__/FABExtended.test.tsx
@@ -61,13 +61,13 @@ it('uses label as default accessibilityLabel', () => {
);
});
-it('respects explicit accessibilityLabel', () => {
+it('respects explicit aria-label', () => {
const { getByTestId } = render(
);
diff --git a/src/components/__tests__/MenuItem.test.tsx b/src/components/__tests__/MenuItem.test.tsx
index db7b30bc21..d240247bef 100644
--- a/src/components/__tests__/MenuItem.test.tsx
+++ b/src/components/__tests__/MenuItem.test.tsx
@@ -50,13 +50,9 @@ describe('Menu Item', () => {
);
});
- it('accepts different values for accessibilityState', () => {
+ it('accepts aria-checked prop', () => {
const { getByTestId } = render(
-
+
);
expect(getByTestId('touchable').props.accessibilityState).toMatchObject({
diff --git a/src/components/__tests__/ProgressBar.test.tsx b/src/components/__tests__/ProgressBar.test.tsx
index c3a89c8749..c30edacbfd 100644
--- a/src/components/__tests__/ProgressBar.test.tsx
+++ b/src/components/__tests__/ProgressBar.test.tsx
@@ -22,12 +22,11 @@ const styles = StyleSheet.create({
},
});
-const a11yRole = 'progressbar';
const triggerLayout = async (
tree: ReturnType
): Promise => {
await act(async () => {
- tree.getByRole(a11yRole).props.onLayout(layoutEvent);
+ tree.getByTestId('progress-bar').props.onLayout(layoutEvent);
});
};
@@ -49,7 +48,7 @@ it('renders progress bar with animated value', async () => {
tree.update();
- expect(tree.getByRole(a11yRole)).toBeTruthy();
+ expect(tree.getByTestId('progress-bar')).toBeTruthy();
});
it('renders progress bar with specific progress', async () => {
@@ -84,12 +83,17 @@ it('renders progress bar with full height on web', () => {
Platform.OS = 'web';
const tree = render();
- expect(tree.getByRole(a11yRole)).toHaveStyle({
+ expect(tree.getByTestId('progress-bar')).toHaveStyle({
width: '100%',
height: '100%',
});
});
+it('has progressbar role', () => {
+ const tree = render();
+ expect(tree.getByTestId('progress-bar').props.role).toBe('progressbar');
+});
+
it('renders progress bar with custom style of filled part', async () => {
const tree = render(
diff --git a/src/components/__tests__/RadioButton/__snapshots__/RadioButton.test.tsx.snap b/src/components/__tests__/RadioButton/__snapshots__/RadioButton.test.tsx.snap
index 5560a80f36..c20910f20e 100644
--- a/src/components/__tests__/RadioButton/__snapshots__/RadioButton.test.tsx.snap
+++ b/src/components/__tests__/RadioButton/__snapshots__/RadioButton.test.tsx.snap
@@ -3,7 +3,6 @@
exports[`RadioButton RadioButton with custom testID renders properly 1`] = `
{
});
});
+describe('Switch accessibility', () => {
+ it('has switch role', () => {
+ const { getByTestId } = render();
+ expect(getByTestId('switch').props.role).toBe('switch');
+ });
+});
+
describe('Switch interaction', () => {
it('toggles to true when off and pressed', () => {
const onValueChange = jest.fn();
- const { getByRole } = render(
-
+ const { getByTestId } = render(
+
);
- fireEvent.press(getByRole('switch'));
+ fireEvent.press(getByTestId('switch'));
expect(onValueChange).toHaveBeenCalledWith(true);
});
it('toggles to false when on and pressed', () => {
const onValueChange = jest.fn();
- const { getByRole } = render(
-
+ const { getByTestId } = render(
+
);
- fireEvent.press(getByRole('switch'));
+ fireEvent.press(getByTestId('switch'));
expect(onValueChange).toHaveBeenCalledWith(false);
});
it('does not fire onValueChange when disabled', () => {
const onValueChange = jest.fn();
- const { getByRole } = render(
-
+ const { getByTestId } = render(
+
);
- fireEvent.press(getByRole('switch'));
+ fireEvent.press(getByTestId('switch'));
expect(onValueChange).not.toHaveBeenCalled();
});
});
diff --git a/src/components/__tests__/TextInput.test.tsx b/src/components/__tests__/TextInput.test.tsx
index 14ded21b21..e70513459a 100644
--- a/src/components/__tests__/TextInput.test.tsx
+++ b/src/components/__tests__/TextInput.test.tsx
@@ -27,6 +27,13 @@ import type { TextInputAccessoryProps } from '../TextInput/TextInputIcon';
const stateOpacity = tokens.md.sys.state.opacity;
+const styles = StyleSheet.create({
+ textInputStyle: {
+ fontSize: 40,
+ letterSpacing: 9,
+ },
+});
+
const defaultI18nIsRTL = I18nManager.isRTL;
const getConstantsOriginal = I18nManager.getConstants.bind(I18nManager);
@@ -248,7 +255,7 @@ it('uses polite aria-live on error supporting text', () => {
);
expect(getByText('Invalid').props['aria-live']).toBe('polite');
- expect(getByTestId('tf-input').props.accessibilityState?.invalid).toBe(true);
+ expect(getByTestId('tf-input').props['aria-invalid']).toBe(true);
});
it('marks the input invalid when error is true without supporting text', () => {
@@ -262,7 +269,7 @@ it('marks the input invalid when error is true without supporting text', () => {
/>
);
- expect(getByTestId('tf-input').props.accessibilityState?.invalid).toBe(true);
+ expect(getByTestId('tf-input').props['aria-invalid']).toBe(true);
expect(getByTestId('tf-input').props.accessibilityHint).toBeUndefined();
});
@@ -322,7 +329,7 @@ it('marks the input as disabled in accessibilityState when disabled is true', ()
/>
);
- expect(getByTestId('tf-input').props.accessibilityState?.disabled).toBe(true);
+ expect(getByTestId('tf-input').props['aria-disabled']).toBe(true);
});
it('renders the input via render with merged props', () => {
@@ -1125,7 +1132,7 @@ it('does not apply the TextInput style prop to prefix or suffix Text', () => {
onChangeText={() => {}}
prefix="$"
suffix="]"
- style={{ fontSize: 40, letterSpacing: 9 }}
+ style={styles.textInputStyle}
testID="tf-input-style"
/>
);
diff --git a/src/components/__tests__/__snapshots__/ActivityIndicator.test.tsx.snap b/src/components/__tests__/__snapshots__/ActivityIndicator.test.tsx.snap
index 43b4eac37e..7e684841e8 100644
--- a/src/components/__tests__/__snapshots__/ActivityIndicator.test.tsx.snap
+++ b/src/components/__tests__/__snapshots__/ActivityIndicator.test.tsx.snap
@@ -2,13 +2,9 @@
exports[`renders colored indicator 1`] = `
Rows per page
@@ -1737,7 +1723,6 @@ exports[`DataTable.Pagination renders data table pagination with options select
testID="button-container"
>
`;
-exports[`renders FAB with accessibilityLabel 1`] = `
+exports[`renders FAB with aria-label 1`] = `
,
,
,
,
,
,
,
,
,
,
@@ -56,21 +48,13 @@ exports[`renders colored progress bar 1`] = `
exports[`renders hidden progress bar 1`] = `
@@ -110,15 +94,10 @@ exports[`renders hidden progress bar 1`] = `
exports[`renders indeterminate progress bar 1`] = `
@@ -158,21 +137,13 @@ exports[`renders indeterminate progress bar 1`] = `
exports[`renders progress bar with specific progress 1`] = `
diff --git a/src/components/__tests__/__snapshots__/Searchbar.test.tsx.snap b/src/components/__tests__/__snapshots__/Searchbar.test.tsx.snap
index bbe1779a66..29b660cbd9 100644
--- a/src/components/__tests__/__snapshots__/Searchbar.test.tsx.snap
+++ b/src/components/__tests__/__snapshots__/Searchbar.test.tsx.snap
@@ -81,9 +81,7 @@ exports[`activity indicator snapshot test 1`] = `
testID="search-bar-icon-container"
>