Nested Focusable Element
Focusable elements should not be nested within clickable parent elements, because they will not properly announce their role to assistive technologies such as TalkBack and Voice Access.
Rule Logic: Nested Focusable Element
Nested Focusable Element is only applicable for accessibility focusable controls that are not interactive but represent a non-accessibility focusable control ancestor that is interactive.
About this Rule
This rule checks for an interactive role on focusable elements.
Impact to Users
Assistive technology normally announces the text content of a clickable element such as a button. However, if there is a focusable item inside of the clickable element, the assistive technology stops scanning and focuses on that inner item instead. This leaves the button with nothing to announce, and so it gets skipped over. The content of the inner item will be announced. The problem is that the user is not made aware of the role of the inner item, or that they can interact with it to trigger an action.
Confirmation
- Turn on TalkBack / screen reader.
- Focus on the view and each of its descendents.
- One of the following will happen:
- Inaccessible: TalkBack reads the text but does not announce a role or ability to interact.
- Accessible: TalkBack will read all text. It will also announce a role and/or indicate how to interact with the element.
How to Fix
XML
Failing Example
In this example, the MaterialCardView
is clickable, but the child LinearLayout
gets focus instead. When assistive technology users interact with the LinearLayout
, it activates the card's click action but doesn't announce that it's clickable. This results in an experience that is not accessible with assistive technology, because the element's role or role description do not indicate that an action is present or what the interaction will do.

<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:layout_margin="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/launch_a_toast"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
Remediation Guidance: Make LinearLayout:focusable
False
Ensure that LinearLayout
does not have a focusable property set to true. In its default state it is false.

<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/launch_a_toast"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
Compose
Failing Example
In this example, the Card
is clickable but the child Row
is focused instead. When assistive technology users interact with the Row
, this acitvates the card's click action but doesn't announce that it is clickable. This results in an experience that is not accessible with assistive technology, because the element's role or role description do not indicate that an action is present or what the interaction will do.

Card(
modifier = Modifier
.clickable {
launchToast(context)
}
) {
Row(
modifier = Modifier
.focusable()
.padding(10.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally)
) {
Text(stringResource(R.string.launch_a_toast))
}
}
Remediation Guidance: Remove Ability to Focus on Descendent Element
Here, the ability to focus has been removed from the Row
element. The Card
will now have text to speak, because it will get information from the Text
. The Card
will now be able to gain focus with assistive technology and will announce the text content. The card will convey to the user that it is clickable via a role description such as "Double-tap to activate", resulting in an accessible experience for the user.

Card(
modifier = Modifier
.clickable {
launchToast(context)
}
) {
Row(
modifier = Modifier
.padding(10.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally)
) {
Text(stringResource(R.string.launch_a_toast))
}
}
.NET MAUI
Failing Example
In this example, the layout is clickable; however, it has been hidden in the accessibility tree. By removing this view, we have stripped the context that this view is functioning as a button, and assistive technology users will not be aware of how they can interact with this view.

<Grid
HorizontalOptions="FillAndExpand"
RowDefinitions="Auto,Auto"
RowSpacing="10"
VerticalOptions="FillAndExpand"
AutomationProperties.IsInAccessibleTree="false">
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Function}"/>
</Grid.GestureRecognizers>
<Label
Grid.Row="1"
FontAttributes="Bold"
FontSize="16"
HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand">
<Label.FormattedText>
<FormattedString>
<Span Text="Text with a clickable parent"/>
</FormattedString>
</Label.FormattedText>
</Label>
</Grid>
Remediation Guidance: Use SemanticProperties.Hint
Property
Accessibility errors can be addressed in one of two ways. The most straightforward way is to remove the AutomationProperties.IsInAccessibleTree="false"
element from the grid view. If that conflicts with other functionality in the app, another way of providing users with the click actions is to set the SemanticProperties.Hint
property with useful context about the type of view a user is interacting with - such as "Button" or "Switch". This will allow assistive technology to properly add the "Double-tap to activate" hint to its readout and give users the feedback they need to interact with the view.

<Grid
HorizontalOptions="FillAndExpand"
RowDefinitions="Auto,Auto"
RowSpacing="10"
VerticalOptions="FillAndExpand">
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Function}"/>
</Grid.GestureRecognizers>
<Label
Grid.Row="1"
FontAttributes="Bold"
FontSize="16"
HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand">
<Label.FormattedText>
<FormattedString>
<Span Text="Text with a clickable parent"/>
</FormattedString>
</Label.FormattedText>
</Label>
</Grid>
React Native
Failing Example
In this example, TouchableOpacity
is clickable but the nested View
has accessible={true}
, which prevents the parent from gaining accessibility focus. The View
will receive focus instead of the clickable TouchableOpacity
, but won't announce that it is interactive. Assistive technology users will hear the product information, but won't know they can tap to view details.

<TouchableOpacity
accessibilityRole="button"
style={styles.productCard}
onPress={() => navigateTo("product")}
>
<View accessible={true}>
<Text>Product Price</Text>
<Text>$10.00</Text>
</View>
</TouchableOpacity>
Remediation Guidance: Add Accessibility Properties
In this remediated example, TouchableOpacity
has proper accessibility properties set directly on it. The properties accessible={true}
and accessibilityRole="button"
ensure assistive technologies announce it as an interactive element, so users understand the content and that it is actionable.

<TouchableOpacity
accessible={true}
accessibilityRole="button"
style={styles.productCard}
onPress={() => navigateTo("product")}
>
<Text>Product Price</Text>
<Text>$10.00</Text>
</TouchableOpacity>
Flutter
Failing Example
In the example below, the GestureDetector
acts as a clickable parent wrapper to the Card
but is not able to gain focus on its own. The Card
acts as the container for its children, so it will gain focus and announce all the content from the child nodes. When assistive technology users focus on the Card
, it will not announce "Double-tap to activate" to the user since the Card
itself is not clickable, even though the parent GestureDetector
is.

GestureDetector(
onTap: () => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Card clicked"),
behavior: SnackBarBehavior.floating,
)
),
child: const Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(
"Card with clickable parent"
),
),
),
);
Remediation Guidance: Do not use a GestureDetector
wrapper
Here, the InkWell
acts as a clickable child of the Card
and will occupy the same dimension as the Card
. The InkWell
now serves as the container that presents all the text content to assistive technology users. The result is one clickable element that announces "Double-tap to activate" to indicate it is interactive.

Card(
child: InkWell(
onTap: () => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Card clicked"),
behavior: SnackBarBehavior.floating,
)
),
child: const Padding(
padding: EdgeInsets.all(16.0),
child: Text(
"Text with clickable parent"
),
),
),
)