Accessibility Styles
Why Accessibility is important
The fundamental purpose of an interface is to provide people with access to information: accessibility is the foundation of an interface. All people experience limitations in their abilities, whether it's temporary, situational or permanent. The aim of accessibility is to remove any obstacles that reduce the experience of using, understanding, and navigating your interface.
This page provides details of the Litho components, methods, nodes, events, and headings available to ensure your interface provides the 'full experience' promoted by Meta.
For information on how Meta is committed to creating a full UI experience for all people, see the Meta Accessibility site.
Implementing Accessibility features
Accessibility properties and events for components can be implemented by adding them to the Style object.
Following is an example of how to combine a Style, that was passed to a Primitive Component, with a newly created Style object that implements accessibility properties and events and will be returned on the LithoPrimitive object from the render() method:
class SimpleImageViewWithAccessibilityPrimitiveComponent(private val style: Style = Style) :
PrimitiveComponent() {
override fun PrimitiveComponentScope.render(): LithoPrimitive {
val a11y =
Style.accessibilityRole(AccessibilityRole.IMAGE)
.accessibilityRoleDescription("Image View")
.importantForAccessibility(ImportantForAccessibility.YES)
.onInitializeAccessibilityNodeInfo { nodeInfo ->
nodeInfo.superDelegate.onInitializeAccessibilityNodeInfo(nodeInfo.host, nodeInfo.info)
nodeInfo.info.addAction(
AccessibilityNodeInfoCompat.AccessibilityActionCompat(
AccessibilityNodeInfoCompat.ACTION_CLICK,
"actionDescriptionText",
),
)
}
return LithoPrimitive(primitive = SimpleImageViewPrimitive, style = a11y + style)
}
}
Accessibility Properties
Accessibility Heading
Whether the view is a heading for a section of content for accessibility purposes.
import com.facebook.litho.accessibility.accessibilityHeading
MyComponent(style = Style.accessibilityHeading(true))
Accessibility Role
The Android Talkback "role" this component has. This will be read out when the view is visited in Talkback mode.
import com.facebook.litho.accessibility.accessibilityRole
import com.facebook.litho.AccessibilityRole
MyComponent(style = Style.accessibilityRole(AccessibilityRole.BUTTON))
Accessibility Role Description
The description for this Component's accessibility role. This will be read out when the view is visited in Talkback mode.
import com.facebook.litho.accessibility.accessibilityRoleDescription
MyComponent(style = Style.accessibilityRoleDescription("Custom action button"))
Content Description
A description of the contents of this Component for accessibility.
import com.facebook.litho.accessibility.contentDescription
MyComponent(style = Style.contentDescription("Profile picture"))
State Description
Sets the state description of the component.
import com.facebook.litho.accessibility.stateDescription
MyComponent(style = Style.stateDescription("Selected"))
Important For Accessibility
Sets whether this Component is "important for accessibility". If it is, it fires accessibility events and is reported to accessibility services that query the screen.
import com.facebook.litho.accessibility.importantForAccessibility
import com.facebook.litho.accessibility.ImportantForAccessibility
MyComponent(style = Style.importantForAccessibility(ImportantForAccessibility.YES))
ImportantForAccessibility values
import com.facebook.litho.accessibility.ImportantForAccessibility
// Automatically determine whether a view is important for accessibility
ImportantForAccessibility.AUTO
// The view is important for accessibility
ImportantForAccessibility.YES
// The view is not important for accessibility
ImportantForAccessibility.NO
// The view is not important for accessibility, nor are any of its descendant views
ImportantForAccessibility.NO_HIDE_DESCENDANTS
Screen Reader Focusable
Sets whether this View should be a focusable element for screen readers.
import com.facebook.litho.accessibility.screenReaderFocusable
MyComponent(style = Style.screenReaderFocusable(true))
Request Initial Accessibility Focus
Sets whether the node has requested initial accessibility focus.
import com.facebook.litho.accessibility.requestInitialAccessibilityFocus
MyComponent(style = Style.requestInitialAccessibilityFocus(true))
Min Duration Between Content Changes
Sets the minimum time duration between two content change events, which is used in throttling content change events in accessibility services.
import com.facebook.litho.accessibility.minDurationBetweenContentChangesMillis
MyComponent(style = Style.minDurationBetweenContentChangesMillis(1000L))
Labeled By
Sets the view which serves as the label of the view represented by this info for accessibility purposes.
import com.facebook.litho.accessibility.labeledBy
MyComponent(style = Style.labeledBy("label_view_tag"))
Pane Title
Visually distinct portion of a window with window-like semantics are considered panes for accessibility purposes. Panes should have descriptive titles.
import com.facebook.litho.accessibility.paneTitle
MyComponent(style = Style.paneTitle("Settings Panel"))
Live Region
Sets the live region mode for this view. This indicates to accessibility services whether they should automatically notify the user about changes to the view's content description or text.
import com.facebook.litho.accessibility.liveRegion
import android.view.View
MyComponent(style = Style.liveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE))
Live Region modes
import android.view.View
// No live region notification
View.ACCESSIBILITY_LIVE_REGION_NONE
// Polite interruption (wait for a pause)
View.ACCESSIBILITY_LIVE_REGION_POLITE
// Assertive interruption (interrupt immediately)
View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
Container Title
Sets the container title for app-developer-defined container which can be any type of ViewGroup or layout. Container title will be used to group together related controls.
import com.facebook.litho.accessibility.containerTitle
MyComponent(style = Style.containerTitle("Form Section"))
Accessibility Events
onInitializeAccessibilityEvent
Initializes an AccessibilityEvent with information about the the host View which dispatched the event.
import com.facebook.litho.accessibility.onInitializeAccessibilityEvent
MyComponent(
style = Style.onInitializeAccessibilityEvent { event ->
// Initialize accessibility event
}
)
onInitializeAccessibilityNodeInfo
Initializes an AccessibilityNodeInfoCompat with information about the host view.
import com.facebook.litho.accessibility.onInitializeAccessibilityNodeInfo
MyComponent(
style = Style.onInitializeAccessibilityNodeInfo { event ->
// Initialize accessibility node info
}
)
onPopulateAccessibilityNode
Gives a chance to the component to implement its own accessibility support.
import com.facebook.litho.accessibility.onPopulateAccessibilityNode
MyComponent(
style = Style.onPopulateAccessibilityNode { event ->
// Populate accessibility node
}
)
onPopulateAccessibilityEvent
Gives a chance to the host View to populate the accessibility event with its text content.
import com.facebook.litho.accessibility.onPopulateAccessibilityEvent
MyComponent(
style = Style.onPopulateAccessibilityEvent { event ->
// Populate accessibility event
}
)
onRequestSendAccessibilityEventWithResult
Called when a child of the host View requests sending an AccessibilityEvent. Return true to allow the event to propagate, or false to block it. Delegate to superDelegate to preserve the View's default behavior.
import com.facebook.litho.accessibility.onRequestSendAccessibilityEventWithResult
MyComponent(
style = Style.onRequestSendAccessibilityEventWithResult { event ->
event.superDelegate.onRequestSendAccessibilityEvent(
event.host,
event.child,
event.event,
)
}
)
onPerformAccessibilityActionWithResult
Called when performing the specified accessibility action on the view. Return true when the action was handled. Return false, or delegate to superDelegate, when it was not.
import android.view.accessibility.AccessibilityNodeInfo
import com.facebook.litho.accessibility.onPerformAccessibilityActionWithResult
MyComponent(
style = Style.onPerformAccessibilityActionWithResult { event ->
if (event.action == AccessibilityNodeInfo.ACTION_CLICK) {
activate()
true
} else {
event.superDelegate.performAccessibilityAction(
event.host,
event.action,
event.args,
)
}
}
)
onSendAccessibilityEvent
Called when Sends an accessibility event of the given type. If accessibility is not enabled this method has no effect.
import com.facebook.litho.accessibility.onSendAccessibilityEvent
MyComponent(
style = Style.onSendAccessibilityEvent { event ->
// Send accessibility event
}
)
onSendAccessibilityEventUnchecked
Sends an accessibility event. This method behaves exactly as sendAccessibilityEvent() but takes as an argument an empty AccessibilityEvent and does not perform a check whether accessibility is enabled.
import com.facebook.litho.accessibility.onSendAccessibilityEventUnchecked
MyComponent(
style = Style.onSendAccessibilityEventUnchecked { event ->
// Send accessibility event unchecked
}
)
onVirtualViewKeyboardFocusChanged
Called when a virtual view child of the host View has changed keyboard focus and gives an opportunity to the parent (the host) to react (changing visual display, etc.)
import com.facebook.litho.accessibility.onVirtualViewKeyboardFocusChanged
MyComponent(
style = Style.onVirtualViewKeyboardFocusChanged { event ->
// Handle virtual view keyboard focus change
}
)
onPerformActionForVirtualViewWithResult
Performs the specified accessibility action on a virtual view child of the host View. Return true when the action was handled, or false otherwise.
Litho does not currently dispatch this handler. Virtual views come only from Spec components that declare extra accessibility nodes, and Litho calls their @OnPerformActionForVirtualView method instead.
import com.facebook.litho.accessibility.onPerformActionForVirtualViewWithResult
MyComponent(
style = Style.onPerformActionForVirtualViewWithResult { event ->
// Perform the action, then return whether it was handled
true
}
)
Focus Order
You can customize the default focus order behavior by creating focus order properties using useFocusOrder() hook and adding them to the Style object. This allows you to tailor the focus order to your specific needs, ensuring that interactive elements are navigable in a logical and predictable manner.
val hideElements = useState { false }
val (first, second, third, fourth, fifth) = useFocusOrder()
return Column(
style = Style.padding(16.dp).contentDescription("Fourth hello!").focusOrder(fourth),
) {
child(
Text(
text = "First hello!",
style =
Style.focusOrder(first).onClick { hideElements.update { !hideElements.value } },
),
)
if (hideElements.value) {
child(Text(text = "Fifth hello!", style = Style.focusOrder(fifth)))
child(TextInput(initialText = "Second hello!", style = Style.focusOrder(second)))
}
child(Text(text = "Third hello!", style = Style.focusOrder(third)))
}