Skip to content

[Image] | (a11y) | Add aria-describedby to Explore Image modal#3504

Merged
nishasy merged 2 commits intomainfrom
explore-modal-describedby
Apr 28, 2026
Merged

[Image] | (a11y) | Add aria-describedby to Explore Image modal#3504
nishasy merged 2 commits intomainfrom
explore-modal-describedby

Conversation

@nishasy
Copy link
Copy Markdown
Contributor

@nishasy nishasy commented Apr 16, 2026

Summary:

The internal audit pointed out that we're missing aria-describedby on the Explore Image modal.
In order to follow best practices, I'm adding that here.

As per the suggestion in the ticket, I'm adding both caption and description IDs if the
caption is present. If there is no caption, then it's just the description ID.

NOTE: This change is not possible to test in VoiceOver since it has a behavior discrepancy -
it will be the same as before adding the aria-describedby. We should be able to see a
difference when using NVDA though.

Update: I confirmed that it reads the describedby content before the close button when using
NVDA on my personal Windows machine!

Issue: https://khanacademy.atlassian.net/browse/LEMS-4046

Test plan:

pnpm jest packages/perseus/src/widgets/image/components/explore-image-modal.test.tsx

Storybook

  • Go to /?path=/story/widgets-image-widget-demo--image
  • Open the Elements tab in dev tools
  • Confirm that the role="dialog" element has aria-describedby that points to the
    caption and description IDs.
Before After
Screenshot 2026-04-16 at 2 10 32 PM Screenshot 2026-04-16 at 2 10 23 PM

nishasy added 2 commits April 16, 2026 14:03
…o Explore Image modal

The internal audit pointed out that we're missing aria-describedby on the Explore Image modal.
In order to follow best practices, I'm adding that here.

As per the suggestion in the ticket, I'm adding both caption and description IDs if the
caption is present. If there is no caption, then it's just the description ID.

NOTE: This change is not possible to test in VoiceOver since it has a behavior discrepancy -
it will be the same as before adding the aria-describedby. We should be able to see a
difference when using NVDA though.

Issue: https://khanacademy.atlassian.net/browse/LEMS-4046

Test plan:
`pnpm jest packages/perseus/src/widgets/image/components/explore-image-modal.test.tsx`

Storybook
- Go to `/?path=/story/widgets-image-widget-demo--image`
- Open the Elements tab in dev tools
- Confirm that the `role="dialog"` element has `aria-describedby` that points to the
  caption and description IDs.
@nishasy nishasy self-assigned this Apr 16, 2026
@github-actions github-actions Bot added schema-change Attached to PRs when we detect Perseus Schema changes in it item-splitting-change labels Apr 16, 2026
@github-actions
Copy link
Copy Markdown
Contributor

npm Snapshot: Published

Good news!! We've packaged up the latest commit from this PR (ffa1ad4) and published it to npm. You
can install it using the tag PR3504.

Example:

pnpm add @khanacademy/perseus@PR3504

If you are working in Khan Academy's frontend, you can run the below command.

./dev/tools/bump_perseus_version.ts -t PR3504

If you are working in Khan Academy's webapp, you can run the below command.

./dev/tools/bump_perseus_version.js -t PR3504

@github-actions github-actions Bot removed the schema-change Attached to PRs when we detect Perseus Schema changes in it label Apr 16, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 16, 2026

🗄️ Schema Change: No Changes ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 16, 2026

Size Change: +100 B (+0.02%)

Total Size: 499 kB

📦 View Changed
Filename Size Change
packages/perseus/dist/es/index.js 196 kB +100 B (+0.05%)
ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 20.5 kB
packages/keypad-context/dist/es/index.js 1 kB
packages/kmath/dist/es/index.js 6.36 kB
packages/math-input/dist/es/index.js 98.5 kB
packages/math-input/dist/es/strings.js 1.61 kB
packages/perseus-core/dist/es/index.item-splitting.js 11.9 kB
packages/perseus-core/dist/es/index.js 25.1 kB
packages/perseus-editor/dist/es/index.js 102 kB
packages/perseus-linter/dist/es/index.js 9.3 kB
packages/perseus-score/dist/es/index.js 9.7 kB
packages/perseus-utils/dist/es/index.js 403 B
packages/perseus/dist/es/strings.js 8.27 kB
packages/pure-markdown/dist/es/index.js 1.39 kB
packages/simple-markdown/dist/es/index.js 6.71 kB

compressed-size-action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 16, 2026

🛠️ Item Splitting: No Changes ✅

@nishasy nishasy requested review from a team and mark-fitzgerald April 16, 2026 21:25
@nishasy nishasy marked this pull request as ready for review April 16, 2026 21:25
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

Copy link
Copy Markdown
Member

@catandthemachines catandthemachines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Added one comment, but non blocking.

linterContext={linterContext}
strings={context.strings}
/>
<div id={longDescId}>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Renderer not have an id property? That's annoying! If you have enough time it think it would be worth while to add it. But non-blocking.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might be the first time I've seen a Renderer linked to an aria-describedby. Although we could drill the id down to the <div> that the Renderer renders, I'm not sure it feels warranted for only one use. Perhaps we could wait and see if this comes up again?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hypothetically, one could argue this is another example of a Renderer wrapped in something with an ID: https://github.com/Khan/perseus/blob/main/packages/perseus/src/widgets/numeric-input/input-with-examples.tsx#L143-L154

It looks like it also needs that wrapper for the classname, so I'm not sure if that's a valid example for this. I'm inclined to leave the code as is for now, since I don't currenly have a way to test that any changes here would be valid (I'd need a windows machine with NVDA).

@nishasy nishasy merged commit b8178b5 into main Apr 28, 2026
21 of 27 checks passed
@nishasy nishasy deleted the explore-modal-describedby branch April 28, 2026 01:39
SonicScrewdriver added a commit that referenced this pull request Apr 28, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @khanacademy/perseus-core@25.0.0

### Major Changes

- [#3511](#3511)
[`15b0193db5`](15b0193)
Thanks [@benchristel](https://github.com/benchristel)! - Remove unused
`static` field from PerseusCSProgramWidgetOptions. Callers should update
test data that constructs `PerseusCSProgramWidgetOptions` to remove the
static field.

### Minor Changes

- [#3441](#3441)
[`de45286302`](de45286)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Creation of new Vector graph and subcomponents.


- [#3433](#3433)
[`b4bb6e2f42`](b4bb6e2)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Creation of initial types and stubs for Vector graph

### Patch Changes

- [#3434](#3434)
[`de2dda0258`](de2dda0)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Implementation of state management logic for new Vector graph

- Updated dependencies
\[[`a5b9105c28`](a5b9105)]:
    -   @khanacademy/kas@2.2.2

## @khanacademy/perseus@77.3.0

### Minor Changes

- [#3441](#3441)
[`de45286302`](de45286)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Creation of new Vector graph and subcomponents.


- [#3433](#3433)
[`b4bb6e2f42`](b4bb6e2)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Creation of initial types and stubs for Vector graph


- [#3494](#3494)
[`8fb79829d0`](8fb7982)
Thanks [@ivyolamit](https://github.com/ivyolamit)! - Interactive Graph:
change asymptote line to dashed for both exponential and logarithm based
on user feedback

### Patch Changes

- [#3523](#3523)
[`c89cdbe2aa`](c89cdbe)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Ensure the default coords for Exponential and Logarithm are slightly
further away from the asymptote.


- [#3508](#3508)
[`16f7f77ba1`](16f7f77)
Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (CX) | Give
explore modal launcher a label saying it has description


- [#3496](#3496)
[`4d923417cd`](4d92341)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Add
fallback label to Numeric Inputs and a linter warning for missing labels
in the editor.


- [#3511](#3511)
[`15b0193db5`](15b0193)
Thanks [@benchristel](https://github.com/benchristel)! - Remove unused
`static` field from PerseusCSProgramWidgetOptions. Callers should update
test data that constructs `PerseusCSProgramWidgetOptions` to remove the
static field.


- [#3504](#3504)
[`b8178b52e7`](b8178b5)
Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (a11y) | Add
aria-describedby to Explore Image modal


- [#3488](#3488)
[`3abc5e8277`](3abc5e8)
Thanks [@mark-fitzgerald](https://github.com/mark-fitzgerald)! - [Free
Response] Add visual regression tests


- [#3493](#3493)
[`11742c2cff`](11742c2)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Implementing bug fix for jumping MovableLines in the Correct Answer
graph in the editor


- [#3483](#3483)
[`7794943ec7`](7794943)
Thanks [@nishasy](https://github.com/nishasy)! - [ColorSync] Numeric
Input - update visual regression tests


- [#3434](#3434)
[`de2dda0258`](de2dda0)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Implementation of state management logic for new Vector graph

- Updated dependencies
\[[`de45286302`](de45286),
[`4d923417cd`](4d92341),
[`15b0193db5`](15b0193),
[`b4bb6e2f42`](b4bb6e2),
[`d3ef4dbcc2`](d3ef4db),
[`a5b9105c28`](a5b9105),
[`de2dda0258`](de2dda0)]:
    -   @khanacademy/perseus-core@25.0.0
    -   @khanacademy/perseus-linter@4.9.5
    -   @khanacademy/perseus-score@8.7.0
    -   @khanacademy/kas@2.2.2
    -   @khanacademy/keypad-context@3.2.44
    -   @khanacademy/kmath@2.4.2
    -   @khanacademy/math-input@26.4.15

## @khanacademy/perseus-editor@30.4.0

### Minor Changes

- [#3441](#3441)
[`de45286302`](de45286)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Creation of new Vector graph and subcomponents.


- [#3443](#3443)
[`a3396604a7`](a339660)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Creation of new Vector Graph Editor


- [#3433](#3433)
[`b4bb6e2f42`](b4bb6e2)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Creation of initial types and stubs for Vector graph


- [#3492](#3492)
[`883133a28f`](883133a)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Add preview
data sanitizer to strip non-serializable values before postMessage

### Patch Changes

- [#3522](#3522)
[`19911cc966`](19911cc)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Label
absolute-value graph start coordinates as "Vertex" and "Arm" in the
editor instead of "Point 1" and "Point 2".


- [#3505](#3505)
[`1ab914fc41`](1ab914f)
Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (CX) | Add
warning for large images


- [#3530](#3530)
[`b5e918e8b3`](b5e918e)
Thanks [@nishasy](https://github.com/nishasy)! - [Image] Update copy of
recalculate button in editor


- [#3434](#3434)
[`de2dda0258`](de2dda0)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! -
Implementation of state management logic for new Vector graph

- Updated dependencies
\[[`de45286302`](de45286),
[`c89cdbe2aa`](c89cdbe),
[`16f7f77ba1`](16f7f77),
[`4d923417cd`](4d92341),
[`15b0193db5`](15b0193),
[`b8178b52e7`](b8178b5),
[`b4bb6e2f42`](b4bb6e2),
[`d3ef4dbcc2`](d3ef4db),
[`3abc5e8277`](3abc5e8),
[`a5b9105c28`](a5b9105),
[`11742c2cff`](11742c2),
[`7794943ec7`](7794943),
[`de2dda0258`](de2dda0),
[`8fb79829d0`](8fb7982)]:
    -   @khanacademy/perseus@77.3.0
    -   @khanacademy/perseus-core@25.0.0
    -   @khanacademy/perseus-linter@4.9.5
    -   @khanacademy/perseus-score@8.7.0
    -   @khanacademy/kas@2.2.2
    -   @khanacademy/keypad-context@3.2.44
    -   @khanacademy/kmath@2.4.2
    -   @khanacademy/math-input@26.4.15

## @khanacademy/perseus-score@8.7.0

### Minor Changes

- [#3442](#3442)
[`d3ef4dbcc2`](d3ef4db)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Added
ability to score Vector Interactive Graphs

### Patch Changes

- Updated dependencies
\[[`de45286302`](de45286),
[`15b0193db5`](15b0193),
[`b4bb6e2f42`](b4bb6e2),
[`a5b9105c28`](a5b9105),
[`de2dda0258`](de2dda0)]:
    -   @khanacademy/perseus-core@25.0.0
    -   @khanacademy/kas@2.2.2
    -   @khanacademy/kmath@2.4.2

## @khanacademy/kas@2.2.2

### Patch Changes

- [#3503](#3503)
[`a5b9105c28`](a5b9105)
Thanks [@benchristel](https://github.com/benchristel)! - Expressions are
now compared more thoroughly. Now we always check that the expressions
evaluate the same with all variables bound to -1, 0, and 1. We also
check more randomly-chosen values: 28 instead of 12.

## @khanacademy/keypad-context@3.2.44

### Patch Changes

- Updated dependencies
\[[`de45286302`](de45286),
[`15b0193db5`](15b0193),
[`b4bb6e2f42`](b4bb6e2),
[`de2dda0258`](de2dda0)]:
    -   @khanacademy/perseus-core@25.0.0

## @khanacademy/kmath@2.4.2

### Patch Changes

- Updated dependencies
\[[`de45286302`](de45286),
[`15b0193db5`](15b0193),
[`b4bb6e2f42`](b4bb6e2),
[`de2dda0258`](de2dda0)]:
    -   @khanacademy/perseus-core@25.0.0

## @khanacademy/math-input@26.4.15

### Patch Changes

- Updated dependencies
\[[`de45286302`](de45286),
[`15b0193db5`](15b0193),
[`b4bb6e2f42`](b4bb6e2),
[`de2dda0258`](de2dda0)]:
    -   @khanacademy/perseus-core@25.0.0
    -   @khanacademy/keypad-context@3.2.44

## @khanacademy/perseus-linter@4.9.5

### Patch Changes

- [#3496](#3496)
[`4d923417cd`](4d92341)
Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Add
fallback label to Numeric Inputs and a linter warning for missing labels
in the editor.

- Updated dependencies
\[[`de45286302`](de45286),
[`15b0193db5`](15b0193),
[`b4bb6e2f42`](b4bb6e2),
[`a5b9105c28`](a5b9105),
[`de2dda0258`](de2dda0)]:
    -   @khanacademy/perseus-core@25.0.0
    -   @khanacademy/kas@2.2.2
    -   @khanacademy/kmath@2.4.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants