You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On Android a keyboard user gets nothing. On web you get the browser's default
outline, so not invisible, just not MD3 and different per browser.
The three that do have one each did it their own way. FAB has a local useFocusRing hook with a reanimated SharedValue and checks document.activeElement. Checkbox uses useState plus src/utils/isKeyboardFocusEvent.ts. Switch uses a SharedValue plus the same
util. All three also carry their own copy of
src/theme/tokens/sys/state.ts already has focusIndicator: { thickness: 3, outerOffset: 2 }. It is just not used in most places.
One thing to know before testing on iOS: onFocus never fires there for a View or Pressable. RCTViewComponentView.mm emits it from becomeFirstResponder only
behind the enableImperativeFocus flag, which defaults off. Android has no such
gate. So the FAB/Checkbox/Switch rings are already inert on iOS, and this is a web
and Android fix.
Expected behaviour
A focus indicator on every interactive component, from one shared implementation and
the existing tokens.
Placement. MD3 puts the ring outside, hence outerOffset. But outside gets
trimmed by a clipping ancestor sized to its content, and lands on the neighbour for
things that sit flush. Chips in a horizontal ScrollView are the obvious case.
material-web hits the same thing and has an inward variant for it.
Colour. MD3 tonal palettes are luminance matched by tone, so a secondary ring
drawn on top of another role at the same tone is about 1:1 and disappears. It needs
to land somewhere with real contrast.
How to reproduce?
cd example && yarn start
Android, hardware keyboard or adb shell input keyevent KEYCODE_TAB. Tab through
the Chip screen. Nothing. Same on List.Item, Segmented Buttons, Radio Button, a
pressable Card.
FAB and Checkbox do show a ring, so focus itself works.
Web, same screens, you get the browser outline instead.
Android drops keyboard focus the moment you touch the screen. Tab again to get back.
Preview
Nothing to show as a still, it only exists while something is focused.
What have you tried so far?
Read every component for existing focus handling to get the table, rather than
trusting the ticket this came from.
RN has outlineWidth / outlineColor / outlineStyle / outlineOffset since
0.77, implemented on both platforms. Measured on iOS sim, android-35 emulator and
expo web: paints on all three, costs no layout, takes its radius from the view it
sits on, survives that view's own overflow: 'hidden', negative offset draws
inside. An ancestor's overflow: 'hidden' does clip it.
Version floor is fine. The react-native-reanimated >= 4.3.0 peer dep already
declares react-native: "0.81 - 0.85".
Current behaviour
Most interactive components have no MD3 keyboard focus indicator.
FAB,FAB.Menu,Checkbox,SwitchRadioButton,Chip,SegmentedButtons,List.Item, pressableCard,Button,IconButton,Menu.Item,Drawer.Item,DataTablerowsOn Android a keyboard user gets nothing. On web you get the browser's default
outline, so not invisible, just not MD3 and different per browser.
The three that do have one each did it their own way.
FABhas a localuseFocusRinghook with a reanimatedSharedValueand checksdocument.activeElement.CheckboxusesuseStateplussrc/utils/isKeyboardFocusEvent.ts.Switchuses aSharedValueplus the sameutil. All three also carry their own copy of
src/theme/tokens/sys/state.tsalready hasfocusIndicator: { thickness: 3, outerOffset: 2 }. It is just not used in most places.One thing to know before testing on iOS:
onFocusnever fires there for aVieworPressable.RCTViewComponentView.mmemits it frombecomeFirstResponderonlybehind the
enableImperativeFocusflag, which defaults off. Android has no suchgate. So the FAB/Checkbox/Switch rings are already inert on iOS, and this is a web
and Android fix.
Expected behaviour
A focus indicator on every interactive component, from one shared implementation and
the existing tokens.
Easy to get wrong:
Pressable's ownfocusedstatefires for clicks too, see Pressable: focus-visible support necolas/react-native-web#1849.
outerOffset. But outside getstrimmed by a clipping ancestor sized to its content, and lands on the neighbour for
things that sit flush. Chips in a horizontal
ScrollVieware the obvious case.material-web hits the same thing and has an
inwardvariant for it.secondaryringdrawn on top of another role at the same tone is about 1:1 and disappears. It needs
to land somewhere with real contrast.
How to reproduce?
cd example && yarn startadb shell input keyevent KEYCODE_TAB. Tab throughthe Chip screen. Nothing. Same on List.Item, Segmented Buttons, Radio Button, a
pressable Card.
Android drops keyboard focus the moment you touch the screen. Tab again to get back.
Preview
Nothing to show as a still, it only exists while something is focused.
What have you tried so far?
trusting the ticket this came from.
outlineWidth/outlineColor/outlineStyle/outlineOffsetsince0.77, implemented on both platforms. Measured on iOS sim, android-35 emulator and
expo web: paints on all three, costs no layout, takes its radius from the view it
sits on, survives that view's own
overflow: 'hidden', negative offset drawsinside. An ancestor's
overflow: 'hidden'does clip it.react-native-reanimated >= 4.3.0peer dep alreadydeclares
react-native: "0.81 - 0.85".Your Environment
main)