react-native-skia icon indicating copy to clipboard operation
react-native-skia copied to clipboard

Canvas is not accessible for people with disabilities

Open GabrieleSuzart opened this issue 1 year ago • 8 comments

Description

I can't use accessibility properties from React Native

I need to configure accessibility for the elements that are rendered over the Canvas, to make it accessible for visually impaired people who use VoiceOver and TalkBack. Such as accessibilityLabel, accessibilityRole and accessibilityHint.

However accessibility properties are not supported on Canvas elements.

Documentation

https://reactnative.dev/docs/accessibility

For example:

import {Canvas, Circle, Group} from "@shopify/react-native-skia";
 
export const HelloWorld = () => {
  const size = 256;
  const r = size * 0.33;
  return (
    <Canvas style={{ flex: 1 }}>
      <Group blendMode="multiply">
        <Circle
          cx={r}
          cy={r}
          r={r}
          color="cyan"
          accessibilityLabel="Sweets with blueberry"
          accessibilityRole="button"
          accessibilityHint="Go to product list"
        />
        <Circle
          cx={size - r}
          cy={r}
          r={r} color="magenta"
          accessibilityLabel="Sweets with strawberry"
          accessibilityRole="button"
          accessibilityHint="Go to product list"
        />
        <Circle
          cx={size/2}
          cy={size - r}
          r={r}
          color="yellow"
          accessibilityLabel="Sweets with lemon"
          accessibilityRole="button"
          accessibilityHint="Go to product list"
        />
      </Group>
    </Canvas>
  );
};

Version

0.1.196

Steps to reproduce

Try implementing accessibility properties on any Canvas element.

Snack, code example, screenshot, or link to a repository

image

GabrieleSuzart avatar Jun 27 '23 16:06 GabrieleSuzart

Hi @GabrieleSuzart - thanks for submitting the issue! It should be possible to add accessibility information to the Canvas - but it will not be possible to add it for the components inside the Canvas.

The reason for this is that components in a Canvas are not real components in the sense that they have a corresponding Android or iOS view backing it. Those components are just a declarative description of the low level drawing operations that React Native Skia will use for rendering a 2D drawing using the GPU.

Due to the possible complex rendering operations it is really hard for us to know the bounding path of the Skia elements - they can be transformed, clipped and combined in ways that makes it heavy to calculate the positions and returning the correct accessibility information when a user explores the rendered drawing.

What we've previously discussed is to suggest building an alternative representation of UX built with regular views and maybe even simplified (compared to the Skia drawing) that can be displayed on top of the Skia drawing when there is a screen reader active.

I'm pinging @colinta here since he has been involved with some of the discussions about this topic - maybe you want to add something here?

chrfalch avatar Jun 28 '23 13:06 chrfalch

@GabrieleSuzart, did you try whether drawing elements in react-native-svg have these accessibility properties?

They employ a different approach to express drawing elements through React components (they utilize shadow nodes: https://reactnative.dev/architecture/render-pipeline), while we use our own React renderer: https://github.com/chentsulin/awesome-react-renderer. I'm curious to know if accessibility properties are available there (the code/documentation seems to suggest so). Currently, the shadow node approach is not possible for us. However, this might change if the React Native architecture allows for creating shadow nodes directly in C++ (vs making a android + ios implementation for each node).

wcandillon avatar Jun 28 '23 14:06 wcandillon

Hello! Thanks for the answer :)

The Path and Svg elements (import { Path, Svg } from 'react-native-svg';) have accessibility properties, as SvgProps extends from ViewProps.

However, ImageSVG (import { ImageSVG } from '@shopify/react-native-skia';) does not have accessibility properties.

Would it be possible to use svg from react-native-svg within Canvas or would some Skia element also receive SvgProps (or ViewProps) properties?

GabrieleSuzart avatar Jun 28 '23 21:06 GabrieleSuzart

Hi, you can't use regular components within a Canvas since a Canvas can only contain Skia components (they're basically descriptions of drawing operations). You can however use accessibility props on the Canvas itself as it is a View that accepts these. So the model is:

Canvas -> View with view props Canvas.children -> Declarative drawing operations that are rendered using the GPU - does not have view props.

The differences compared to react-native-svg is that in RNSvg all nodes are essentially views that has view properties including accessibility props.

chrfalch avatar Jun 29 '23 07:06 chrfalch

I'll close this one for now, please open a discussion if needed.

chrfalch avatar Jul 02 '23 08:07 chrfalch

Could we reopen this issue and mark it as a feature request?

wcandillon avatar Jul 05 '23 07:07 wcandillon

Agree

chrfalch avatar Jul 05 '23 08:07 chrfalch

@GabrieleSuzart There is a solution that we use for integrating Gesture handler and Skia which consisting of overlaying native views over the canvas: https://github.com/Shopify/react-native-skia/blob/main/example/src/Examples/Stickers/Stickers.tsx#L27 (in the example you can see that each sticker is drawn on the canvas and has a corresponding native view on top of it).

Presumably the same technic could be used for accessibility.

If at some point the new React Native architecture allows for creating shadow nodes in C++, this is definitely something that we will consider.

wcandillon avatar Jul 07 '23 19:07 wcandillon

:tada: This issue has been resolved in version 1.3.3 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

github-actions[bot] avatar Jun 06 '24 14:06 github-actions[bot]