Skip to main content

Accessibility States

SeveritySerious
Accessibility PrincipleUnderstandable
Affected usersVisual
Success criterion4.1.2

Accessibility states are attributes you add to a component to tell assistive technologies — such as screen readers (VoiceOver, TalkBack) and voice control software — about its current condition. They communicate things like whether a checkbox is ticked, a button is disabled, or a section is expanded.

Without these attributes, a screen reader user may see the correct label and role but have no way to know the element's current state.

aria-busy

• Severity: Serious

Indicates that an element is being updated and that assistive technologies should wait until the update is complete before announcing the change.[^1]

TypeDefault
booleanfalse

Expectations

Assistive Technology: Screen Reader
  • When: The user triggers (double tap) a component
    • And: The component is performing a long (or async) task
      • Then: The Screen Reader announces the component as busy

Assistive Technology: Voice Control
  • When: The user pronounces the label while the component is busy
    • Then: If the component is non-interactive while busy, Voice Control shows no interactive target — the command has no effect

Screen Reader behaviour

Assuming we have a button that adds the given product ID to the cart, which requires an API call:

const AddToCart = ({ productID }: { productID: string }) => {
const { addToCart, isAddingToCart } = useQuery(ADD_TO_CART);

const onPress = async () => {
const result = await addToCart();
};

return (
<Pressable
accessibilityLabel="Add to cart"
accessibilityRole="button"
ariaBusy={isAddingToCart}
onPress={isAddingToCart ? undefined : onPress}>
{isAddingToCart} ? <ActivityIndicator /> : <Text>Add to cart</Text>
</Pressable>
);
};

In the example, while the adding action is happening, the button:

  • Ignores any press action
  • Shows a loading spinner

While this works fine for sighted users, we must add the ariaBusy={isAddingToCart} property for visually impaired users to signal that the action is still happening.

The user double taps on the example component:

VoiceOverTalkback
plays a sound as confirmationGood

The user focuses again on the component while the API is still in flight:

VoiceOverTalkback
Add to cart, busy, button, double tap to activateGood

aria-checked

• Severity: Serious

Indicates the state of a checkable element. This field can either take a boolean or the "mixed" string to represent mixed checkboxes.

TypeDefault
boolean, 'mixed'false

Expectations

Assistive Technology: Screen Reader
  • When: The component can be toggle
    • And: Receives the focus
      • Then: The checked status is announced
      • And: And the accessibility label is announced
      • And: And the accessibility role is announced
      • And: And the available action is announced

Assistive Technology: Voice Control
  • When: The user pronounces the label
    • Then: The Voice Control software recognizes the label
      • And:
          The Voice Control software toggles the element — the checked state does not affect command recognition
caution

aria-checked is not to be confused with aria-selected. aria-checked is only meant to be used with checkboxes and toggle buttons.

Screen Reader behaviour

type ToggleButtonProps = {
checked: boolean;
label: string;
};

export const ToggleButton = ({ checked, label }: ToggleButtonProps) => {
return (
<Pressable
accessibilityLabel={label}
ariaChecked={checked}
ariaRole="button">
{label}
</Pressable>
);
};

Assuming the button label is: Add me to the list

The user selects the component

StateVoiceOverTalkback
checkedticked, Add me to the list, tickbox, double tap to toggleGood
not checkednot ticked, Add me to the list, tickbox, double tap to toggleGood

The user double taps on the example component:

New stateVoiceOverTalkback
checkedtickedGood
not checkednot tickedGood

aria-disabled

• Severity: Serious

Indicates that the element is visible but disabled — it cannot be edited or interacted with.

TypeDefault
booleanfalse

Expectations

Assistive Technology: Screen Reader
  • When: The component is disabled
    • And: Receives the focus
      • Then: The Screen Reader announces its disabled status first
      • And: The accessibility label is announced
      • And: The accessibility role is announced

Assistive Technology: Voice Control
  • When: The user pronounces the label
    • Then: Disabled elements cannot be targeted by voice commands — Voice Control does not show an interactive overlay on disabled components

Screen Reader behaviour

const AddToCart = ({ disabled }) => {
return (
<Pressable
accessibilityLabel="Add to cart"
accessibilityRole="button"
disabled={disabled}>
Add to cart
</Pressable>
);
};

When the component receives the focus

Is Disabled?VoiceOverTalkback
falseAdd me to the cart, button, double tap to activateAdd me to the cart, button, double tap to activateGood
truedimmed, Add me to the cart, buttondisabled, Add me to the cart, buttonGood

aria-expanded

• Severity: Serious

Indicates whether an expandable element is currently expanded or collapsed.

TypeDefault
booleanfalse

Expectations

Assistive Technology: Screen Reader
  • When: The user triggers (double tap) a collapsable component, i.e. Accordion
    • And: Its content is expanded/collapsed
      • Then: The Screen Reader announces the component as expanded/collapsed

Assistive Technology: Voice Control
  • When: The user pronounces the label
    • Then: The Voice Control software recognizes the label
      • And:
          The Voice Control software executes the action — the expanded or collapsed state does not affect command recognition

Screen Reader behaviour

export const Content = ({ content }) => {
const [isShowingMore, setIsShowingMore] = React.useState(false);

return (
<View>
<Text numberOfLines={isShowingMore ? undefined : 2}>{content}</Text>
<Pressable
accessibilityLabel="Show more"
accessibilityRole="button"
ariaExpanded={isShowingMore}
onPress={() => setIsShowingMore(showMore => !showMore)}>
{isShowingMore ? 'Show less' : 'Show more'}
</Pressable>
</View>
);
};

When the component receives the focus

Is the content expanded?VoiceOverTalkback
falseShow more, collapsed button, double tap to activateGood
trueShow less, expanded, button, double tap to activateGood

When the component is activated (double-tap)

Is the new state expanded?VoiceOverTalkback
falseShow more, collapsed button, double tap to activateGood
trueShow less, expanded, button, double tap to activateGood

aria-selected

Indicates whether a selectable element is currently selected or not.

TypeDefault
booleanfalse

Expectations

Assistive Technology: Screen Reader
  • When: The user selects an option component, i.e. radio button
    • Then: The Screen Reader announces the component selected state first

Assistive Technology: Voice Control
  • When: The user pronounces the label
    • Then: The Voice Control software recognizes the label
      • And:
          The Voice Control software selects the element — the selected state does not affect command recognition

Screen Reader behaviour

const OptionButton = ({ selected, label }) => {
return (
<Pressable
accessibilityLabel={label}
accessibilityRole="button"
ariaSelected={selected}>
<Text>{label}</Text>
</Pressable>
);
};

const TestScreen = () => {
const [selectedOption, setSelectedOption] = React.useState('Big');

return ['Big', 'Medium', 'Small'].map(size => {
return (
<Option
label={size}
selected={optionSelected}
onPress={() => setSelectedOption(size)}
/>
);
});
};

When the component receives the focus

Is Selected?VoiceOverTalkback
falseaccessibility label, button, double tap to activateGood
trueSelected, accessibility label button, double tap to activateGood

When the component is activated (double-tap)

Is the new state selected?VoiceOverTalkback
trueaccessibility label, selectedGood
falseGood

AMA dev runtime errors


NO_ACCESSIBILITY_STATE_SET MUST

This error is raised when the UI state changes but assistive technologies are not informed — for example, a component's visual state updates without a corresponding accessibility state attribute.

note

This rule can be disabled by turning off the UI check in the ama.config.json file.

Best Practices

Use the right state for the right meaning

aria-checked and aria-selected are not interchangeable:

  • Use aria-checked for checkboxes and toggle buttons.
  • Use aria-selected for items within a selection group — tabs, options in a list, radio-style buttons.

Using the wrong one causes screen readers to announce incorrect semantics to the user.

Keep state in sync with visual presentation

The state attribute must always reflect what the user sees. If a checkbox appears ticked, aria-checked must be true. Mismatches between visual and accessible state confuse all AT users and can fail automated accessibility audits.

Use aria-disabled to keep elements discoverable

A hidden or removed element cannot be found at all. Use aria-disabled when the element should remain visible and focusable for context, but not operable — for example, a "Submit" button that is disabled until a form is complete.

Announce aria-busy during async operations

Whenever a component triggers an async action and temporarily ignores interaction, set ariaBusy={true}. This prevents screen reader users from wondering why their action had no effect.

External references