Writing accessible canvas descriptions
In this tutorial, you'll learn how to use describe() , describeElement(), gridOutput(), and textOutput(). These functions add labels to your canvas so that it’s readable for screen readers and other assistive technologies.
What is labeling?
When you use the createCanvas() function, you create a canvas HTML element. This canvas element displays the image generated by your code as a bitmap (a raster graphic made up of pixels). Unlike most HTML elements, the canvas doesn’t provide any description about its contents to screen readers. That’s why we created the describe(), describeElement(), gridOutput(), and textOutput() functions. These functions add labels to your canvas that tell the screen reader how to describe it.
Why labeling matters
Screen readers (and text-to-speech software) are helpful for lots of people, regardless of ability or context. For example, a visually impaired person searching the web might use a screen reader to understand the contents of a site. If a site’s code isn’t properly labeled for assistive technologies, the screen reader software won’t be able to communicate what’s on the site to its user. Someone else might be using a text-to-speech software because they have dyslexia and find listening to the site’s content more comprehensible than reading it. There are also people who use these assistive software to multi-task, so they can listen to an article on the web and wash dishes, or complete other chores.
No matter the purpose or person, making sure your code is readable by these assistive software allows more people to engage with your work in meaningful ways.
Available labeling functions
p5.js offers four different functions for labeling your canvas:
- describe() provides a description of the canvas contents. This function's parameters include: text, the label itself; and display, an optional parameter to set the visibility of the label.
- describeElement() describes a specific element or a specific grouping of elements in a canvas. This function's parameters include: name, the title for the label; text, the label itself; and display, an optional parameter to set the visibility of the label.
- textOutput() generates a list describing the canvas size, color, as well as each visual element’s color, position, and the area it covers within the canvas. This function’s only parameter is display, an optional parameter to set the visibility of the label.
- gridOutput(), like textOutput(), generates a list of the canvas' qualities and elements. Along with this list, this function also creates an HTML table that plots the spatial location of each shape within the canvas. This function's only parameter is display, an optional parameter to set the visibility of the label.
Your project's code should be near completion before you begin labeling. To write clear and effective labels, you should have a clear understanding about what visuals your code creates within the canvas element.
For example, if you started writing your labels before you had a clear understanding of the resulting visual of your canvas, your labels and your visuals may communicate different messages, like the code example below:
Steps for labeling your p5.js code
1. Plan your labeling strategy
Your labeling strategy will change based on your project’s complexity and purpose.
No matter how complicated your project may be, always provide a brief description of your canvas in setup() using the describe() function. If you do not provide any labels in your code, screen readers will describe your canvas as a blank HTML element.
Place this label in the setup() section of your code, and provide a 1-3 sentence description of your canvas in its text parameter. This description should only provide details about the visual elements of your canvas.
As stated previously, you do not need to begin your description with “A p5 canvas element…” or anything similar, since the screen reader will declare the element type before reading your label.
The textOutput() and gridOutput() functions can describe the shapes on your canvas, but they can’t interpret your intention in using the shapes. Keep context in mind when choosing which function(s) to use. Is it better to describe the flower as “eight circles and a rectangle”, or as “a flower with red petals and a green stem”? What kind of labeling will provide the best description of your canvas? If you are creating larger visuals with many shapes, use describeElement() to label each group of shapes.
Do not use both the textOutput() and gridOutput() functions to describe the same canvas. Using both will cause similar descriptions to appear twice, which is confusing to screen readers. The same goes for using textOutput() or gridOutput() with describeElement() labels. It’s best to choose one function to supplement your describe() label.
Use vanilla ARIA labeling and custom-built fallback labels instead of p5’s labeling functions if your canvas:
- Has content that changes extensively via external interactive elements (elements outside the canvas)
- Interacts with DOM elements written outside of the canvas code
- Requires the user’s attention if the canva's visual content changes
- Has complex element layouts that cannot be accurately labeled with the describe(), describeElement(), textOutput(), or gridOutput() functions
2. Write your main and supporting label(s)
Begin labeling your canvas using the function(s) that best serve your users.
While labeling, only provide descriptions of the visual aspects of your canvas. You don’t need to describe how or what functions create the visuals present on the canvas, only how the end result visuals appear within the canvas.
When using the describeElement() function to label your code, provide a unique title and a description no more than 1-2 sentences long. Only label the parts of your code that depict the most important visual aspects of your canvas.
Within each describeElement() label, discuss the important qualities of that element. Is the element animated? Is the element interactive? What meaning does the element provide to the project?
If your canvas contains any text() elements that are important to the general understanding of the image, make a separate label for them. Label any legible text with quotation marks around it in the label, as in describeElement("Text", "The words 'hello, world' displayed in green at the center of a black canvas.").
You don’t need to start each label with “A p5 canvas…” or something similar. The screen reader will call out the element type before reading your labels:
Limit the number of describeElement() functions present within your code as much as possible. If you have to use more than 10 describeElement() functions to describe your canvas, consider using a labeling strategy that affords more complexity (such as vanilla ARIA labeling).
Using gridOutput() or textOutput()
gridOutput() and textOutput() generate their information based on the code of the visual element, such as its size, color, and shape. Unlike describeElement(), you only need to use one label to describe all your canvas's visual elements.
Projects with animated or interactive elements
Individual interactive elements, such as HTML buttons, dropdowns, or inputs, don’t need labels. These elements are built outside of the p5.js canvas and are interpreted by screen readers. However, this means the gridOutput() and textOutput() functions won’t provide any information about these interactive inputs.
If a canvas element is animated and/or interactive, represent its current state or qualities in the label. So long as you place the functions within the draw() function, they will automatically update with the shape’s new information (except for textOutput() and gridOutput(), which will update even when listed in setup()). If you are using describeElement(), use template strings to update the element’s description:
Labeling do’s and don’ts
Don’t use screen reader labels as a way of commenting your code. Labels should only summarize the resulting visual elements within a canvas. If you overuse screen reader labels, you may end up complicating the screen reader’s interpretation of the canvas rather than helping it.
Do make your label descriptions short and accurate. Use full sentences for your labels, and write in the present tense when describing elements.
3. Test your labels
Be sure to test your labels before publishing your sketch. Labels are only available to screen readers by default.To see the output during development, pass LABEL as the last argument to the function.
When testing your labels, consider the following questions:
- Do your canvas labels provide enough information for someone to understand the sketch’s purpose?
- If this canvas exists on a web page among other content, would someone have a good understanding of how the canvas relates to its surrounding context?
Be sure to remove the LABEL argument once you’ve tested the output. With LABEL active, screen readers are forced to read the fallback text and the visible label text when focused on the canvas. This is confusing for them.
You may also download a screen reader and use it to test your code. For more information about using screen readers, visit W3 School’s "Accessibility Screen Readers".
Once you've tested your labels, your canvas should be accessible to screen reader technology!
If you would like more information about ARIA labeling, visit MDN’s ARIA.
Notice any errors or typos? Please let us know. If you would like to contribute to this tutorial, feel free to issue a pull request!