Add Button role to clickable icons and text on login/onboarding screens

Several clickable elements on the login and onboarding flows (the
account provider list items, the search clear icon, the login clear
icon, and the hidden dev-mode version tap) use plain
Modifier.clickable without a semantics role. Screen readers announce
these as generic elements instead of buttons, so users relying on
TalkBack cannot tell they are interactive.

Add role = Role.Button to each clickable modifier, and reuse the
existing clear-icon content description as onClickLabel where one is
available.
This commit is contained in:
Jürgen Wischer
2026-07-15 22:07:33 +02:00
parent 3bb7fe97e6
commit 9c6e7b4464
5 changed files with 26 additions and 11 deletions
@@ -18,6 +18,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
@@ -40,7 +41,7 @@ fun AccountProviderOtherView(
Column(
modifier = modifier
.fillMaxWidth()
.clickable { onClick() }
.clickable(role = Role.Button) { onClick() }
) {
HorizontalDivider()
Row(
@@ -19,6 +19,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
@@ -45,7 +46,7 @@ fun AccountProviderView(
Column(
modifier = modifier
.fillMaxWidth()
.clickable { onClick() }
.clickable(role = Role.Button) { onClick() }
) {
HorizontalDivider()
Column(
@@ -36,6 +36,7 @@ import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalAutofillManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.contentType
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.input.ImeAction
@@ -211,10 +212,15 @@ private fun LoginForm(
singleLine = true,
trailingIcon = if (loginFieldState.isNotEmpty()) {
{
Box(Modifier.clickable {
loginFieldState = ""
eventSink(LoginPasswordEvents.SetLogin(""))
}) {
Box(
Modifier.clickable(
onClickLabel = stringResource(CommonStrings.action_clear),
role = Role.Button,
) {
loginFieldState = ""
eventSink(LoginPasswordEvents.SetLogin(""))
}
) {
Icon(
imageVector = CompoundIcons.Close(),
contentDescription = stringResource(CommonStrings.action_clear),
@@ -27,6 +27,7 @@ import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
@@ -336,7 +337,7 @@ private fun OnBoardingButtons(
} else {
Text(
modifier = Modifier
.clickable {
.clickable(role = Role.Button) {
state.eventSink(OnBoardingEvents.OnVersionClick)
}
.padding(16.dp),
@@ -34,6 +34,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.PreviewParameter
@@ -125,10 +126,15 @@ fun SearchAccountProviderView(
singleLine = true,
trailingIcon = if (userInputState.isNotEmpty()) {
{
Box(Modifier.clickable {
userInputState = ""
eventSink(SearchAccountProviderEvents.UserInput(""))
}) {
Box(
Modifier.clickable(
onClickLabel = stringResource(CommonStrings.action_clear),
role = Role.Button,
) {
userInputState = ""
eventSink(SearchAccountProviderEvents.UserInput(""))
}
) {
Icon(
imageVector = CompoundIcons.Close(),
contentDescription = stringResource(CommonStrings.action_clear)