Accessibility

Overview

To better support visually impaired users, mini apps support configuring accessibility attributes. Accessibility features are available in screen reader mode. You can enable screen readers as follows:

  • iOS: Settings → General → Accessibility → VoiceOver
  • Android: Settings → Accessibility → TalkBack

Take the View component as an example. You can add role and aria-label attributes to it. The role attribute defines the semantic role of the component — for instance, setting it to 'img' causes the screen reader to announce "image" when focused, and setting it to 'button' causes it to announce "button". The aria-label attribute provides additional descriptive text that the screen reader will announce when the element is focused.

Accessibility Styles

The base library automatically manages the accessibility style switch. When accessibility styles are enabled, it adds data-a11y="true" to the HTML root node; when disabled, it removes the attribute. You do not need to set this attribute manually. Instead, use it in selectors to provide higher contrast, clearer focus states, or larger touch targets in accessibility mode.

[data-a11y='true'] .action-btn {
  min-height: 96rpx;
  outline: 4rpx solid #1677ff;
}

The following ARIA attributes can be passed as props to any component to define custom accessibility semantics.

Accessibility Properties

PropertyDescription
roleSemantic role, e.g. button, checkbox, slider, link
aria-labelText read aloud by assistive technology to describe the element
aria-labelledbyReferences the id of another element whose text serves as the label for this element (useful for elements with a separate heading)
aria-describedbyReferences the id of another element whose text provides a description for this element
aria-disabledWhether the element is disabled
aria-hiddenWhen 'true', assistive technology ignores this element and its subtree; useful for purely decorative content
aria-checkedWhether the element is checked (applies to checkbox, radio, switch)
aria-selectedWhether the element is selected (applies to list items, tabs, and other selectable scenarios)
aria-expandedWhether the element is expanded (applies to collapsible panels, etc.)
aria-haspopupWhether the element has an associated popup (e.g. a dropdown menu)
aria-liveLive region update policy. Values: off (default, no announcement), polite (announces after update completes), assertive (interrupts current announcement immediately)
aria-atomicUsed with aria-live. When 'true', assistive technology announces the entire live region; when 'false', only the changed portion is announced
aria-relevantUsed with aria-live. Specifies what types of changes trigger an announcement. Values: additions, removals, text, all
aria-requiredWhether the form element is required (applies to input, textarea, etc.)
aria-flowtoSpecifies the id of the next element in reading order, overriding the default document order
aria-valuetextHuman-readable text for the current value of a range element (takes precedence over aria-valuenow when announced)
aria-valueminMinimum value of a range element (applies to slider)
aria-valuemaxMaximum value of a range element (applies to slider)
aria-valuenowCurrent value of a range element (applies to slider)
tabindexPosition of the element in Tab key navigation order; 0 makes it focusable, -1 removes it from Tab order

Built-in ARIA Properties

The following components have built-in ARIA attributes that are set automatically — no manual configuration required:

ComponentAccessibility Properties
Buttonrole="button" aria-disabled
Input / Textareaaria-disabled
Checkboxrole="checkbox" aria-checked aria-disabled
Radiorole="radio" aria-checked aria-disabled
Switchrole="switch" aria-checked aria-disabled
Sliderrole="slider" aria-valuemin aria-valuemax aria-valuenow aria-disabled
Pickeraria-haspopup="true" aria-disabled
Navigatorrole="link" tabindex="0"

Examples

Add role and aria-label to a View

import React from 'react';
import { View, Text } from '@ray-js/ray';

export default function AccessibilityDemo() {
  return (
    <View
      role="button"
      aria-label="Close dialog"
      tabindex="0"
      style={{ padding: '20rpx', background: '#f0f0f0', display: 'inline-block' }}
    >
      <Text>x</Text>
    </View>
  );
}

Frequently Asked Questions

I passed a role to Button, but it doesn't seem to work. Why?

Button has a built-in role="button". Any custom role passed to it will be overridden by the built-in value. To use a custom semantic role, use View or another element without a built-in role.

Which takes precedence when both aria-label and inner text are present?

Assistive technology generally prioritizes aria-label over inner text. If the component's inner text already conveys the meaning clearly, there is no need to set aria-label. For elements like icon-only buttons that lack descriptive text, always set aria-label.

How should I choose a value for tabindex?

Use only 0 or -1. A value of 0 adds the element to the natural Tab order; -1 makes it programmatically focusable but excludes it from Tab navigation. Avoid positive integers, as they disrupt the natural Tab order.