Skip to content

Conversation

@marcysutton
Copy link
Member

@marcysutton marcysutton commented Nov 25, 2025

Summary:

After making bugfixes and updates to conditionally rendered modals, I figured we should update the docs.

Note: the ModalLauncher and DrawerLauncher descriptions are only rendered from stories files

Issue: WB-2103

Test plan:

  1. Review Modal overview, ModalLauncher, and DrawerLauncher docs!

@marcysutton marcysutton self-assigned this Nov 25, 2025
@changeset-bot
Copy link

changeset-bot bot commented Nov 25, 2025

🦋 Changeset detected

Latest commit: 9d29c92

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@khan-actions-bot
Copy link
Contributor

khan-actions-bot commented Nov 25, 2025

Gerald

Required Reviewers
  • @Khan/wonder-blocks for changes to .changeset/grumpy-dingos-confess.md, __docs__/wonder-blocks-modal/_overview_.mdx, __docs__/wonder-blocks-modal/drawer-launcher.stories.tsx, __docs__/wonder-blocks-modal/flexible-dialog.stories.tsx, __docs__/wonder-blocks-modal/modal-launcher.stories.tsx, __docs__/wonder-blocks-modal/modal-panel.stories.tsx, packages/wonder-blocks-modal/src/components/drawer-launcher.tsx

Don't want to be involved in this pull request? Comment #removeme and we won't notify you of further changes.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 25, 2025

Size Change: 0 B

Total Size: 109 kB

ℹ️ View Unchanged
Filename Size
packages/wonder-blocks-accordion/dist/es/index.js 3 kB
packages/wonder-blocks-announcer/dist/es/index.js 1.74 kB
packages/wonder-blocks-badge/dist/es/index.js 2.02 kB
packages/wonder-blocks-banner/dist/es/index.js 2.01 kB
packages/wonder-blocks-birthday-picker/dist/es/index.js 1.92 kB
packages/wonder-blocks-breadcrumbs/dist/es/index.js 755 B
packages/wonder-blocks-button/dist/es/index.js 4.25 kB
packages/wonder-blocks-card/dist/es/index.js 1.06 kB
packages/wonder-blocks-cell/dist/es/index.js 2.19 kB
packages/wonder-blocks-clickable/dist/es/index.js 2.66 kB
packages/wonder-blocks-core/dist/es/index.js 2.48 kB
packages/wonder-blocks-data/dist/es/index.js 5.48 kB
packages/wonder-blocks-dropdown/dist/es/index.js 19.4 kB
packages/wonder-blocks-form/dist/es/index.js 6.2 kB
packages/wonder-blocks-grid/dist/es/index.js 1.24 kB
packages/wonder-blocks-icon-button/dist/es/index.js 3.2 kB
packages/wonder-blocks-icon/dist/es/index.js 1.91 kB
packages/wonder-blocks-labeled-field/dist/es/index.js 3.48 kB
packages/wonder-blocks-layout/dist/es/index.js 1.63 kB
packages/wonder-blocks-link/dist/es/index.js 1.52 kB
packages/wonder-blocks-modal/dist/es/index.js 7.06 kB
packages/wonder-blocks-pill/dist/es/index.js 1.31 kB
packages/wonder-blocks-popover/dist/es/index.js 4.3 kB
packages/wonder-blocks-progress-spinner/dist/es/index.js 1.48 kB
packages/wonder-blocks-search-field/dist/es/index.js 1.1 kB
packages/wonder-blocks-styles/dist/es/index.js 464 B
packages/wonder-blocks-switch/dist/es/index.js 1.55 kB
packages/wonder-blocks-tabs/dist/es/index.js 3.71 kB
packages/wonder-blocks-testing-core/dist/es/index.js 3.25 kB
packages/wonder-blocks-testing/dist/es/index.js 978 B
packages/wonder-blocks-theming/dist/es/index.js 384 B
packages/wonder-blocks-timing/dist/es/index.js 1.37 kB
packages/wonder-blocks-tokens/dist/es/index.js 5.01 kB
packages/wonder-blocks-toolbar/dist/es/index.js 906 B
packages/wonder-blocks-tooltip/dist/es/index.js 6.4 kB
packages/wonder-blocks-typography/dist/es/index.js 1.57 kB

compressed-size-action

@github-actions
Copy link
Contributor

github-actions bot commented Nov 25, 2025

A new build was pushed to Chromatic! 🚀

https://5e1bf4b385e3fb0020b7073c-kditebicgj.chromatic.com/

Chromatic results:

Metric Total
Captured snapshots 285
Tests with visual changes 0
Total stories 742
Inherited (not captured) snapshots [TurboSnap] 157
Tests on the build 442

Copy link
Member

@beaesguerra beaesguerra left a comment

Choose a reason for hiding this comment

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

Thanks for adding these docs!

@marcysutton
Copy link
Member Author

Added fixes for the Modal a11y issues in stories! https://khanacademy.atlassian.net/browse/WB-2161

Copy link
Member

@beaesguerra beaesguerra left a comment

Choose a reason for hiding this comment

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

Thanks for taking a look at the modal a11y issues! I left some questions around whether the original examples were valid use cases. I wanted to check first since this may signal underlying a11y issues for existing usage that follow the same patterns in the original examples. Let me know what you think!

(Also, I see there are similar a11y issues in other modal stories. If it's something we can fix at the component level, then we can address the others too! Sorry I didn't list out all the modal stories with issues in the ticket!)

<View style={styles.modalPositioner}>
<FlexibleDialog
aria-labelledby="main-heading"
title={
Copy link
Member

Choose a reason for hiding this comment

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

Does this mean the heading should always be in the title prop? Are there use cases that consumers would need where it is part of the content?

I was assuming manually configuring aria-labelledby meant a custom implementation of the title was needed, since using the title prop will auto-wire up the attributes already!

const renderedTitle =
title == null ? null : typeof title === "string" ? (
<Heading id={headingId}>{title}</Heading>
) : (
// Augment heading element with ID/testId
React.cloneElement(title, {
id: headingId,
testId: "title-heading-wrapper",
})
);

I also noticed that the aria-labelledby prop provided by the consumer doesn't end up getting used (other aria attributes are applied though!). This might be what was causing an issue with the original example?

aria-label={accessibilityProps["aria-label"]}
aria-labelledby={headingId}
aria-describedby={accessibilityProps["aria-describedby"]}

Copy link
Member Author

Choose a reason for hiding this comment

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

The component is intended to use the title prop so naming can be handled automatically, with the option for it to be inserted into content with the title render prop. But the story originally included an aria-labelledby example that didn't work properly, and it was a little confusing outside of the happy path. I opened a separate ticket to revisit naming with aria-labelledby, since it's a little more involved than fixing up some stories: https://khanacademy.atlassian.net/browse/WB-2168

content={
<>
{longBody}
{button}
Copy link
Member

Choose a reason for hiding this comment

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

If there is scrollable content in a modal and no interactive elements within it (like the original example without the button), should we add tabIndex=0 to the scrollable container, similar to what's done in frontend with ScrollableView?

I'm wondering if there are valid use cases where there might not be an interactive element within the scrollable modal content that would prevent scrolling via keyboard! What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

I made some updates to ensure scrollability with the keyboard on those internal View components, and added the global focus style.

I will add that I don't love wrapping an internal View with tabIndex=0 though, because it needs an interactive role and accessible name for screen reader users as well. But these are already provided at the dialog level, and using the same ID reference for this scrollable container is doubly confusing...so I'm at a loss for how to name it. Maybe "scroll container" or something? That seems more like an aria-roledescription than a name, since it wouldn't really be unique.

What I'd love to see is some dynamic keyboard scroll handling so consumers don't have to manually add tabIndex attributes, accessible names, and widget roles. Ideally the browser would deal with it. But maybe ModalPanel (and ScrollableView in frontend, for that matter) could detect overflow scrolling as well as interactive components to deal with it conditionally.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Thank you for creating a ticket! I agree that this would probably need a broader solution! The keyboard scrolling issue is also related to the SimpleTable a11y fixes I'm working on in https://github.com/Khan/frontend/pull/5786

Ideally the browser would deal with it. But maybe ModalPanel (and ScrollableView in frontend, for that matter) could detect overflow scrolling as well as interactive components to deal with it conditionally.

FWIW, Chrome + Firefox on macOS will automatically make a scrollable div focusable! Safari does not 😢 https://jsfiddle.net/qorx1a5b/3/

@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

npm Snapshot: NOT Published

🤕 Oh noes!! We couldn't find any changesets in this PR (8a2046f). As a result, we did not publish an npm snapshot for you.

Copy link
Member

@beaesguerra beaesguerra left a comment

Choose a reason for hiding this comment

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

Approving again for the modal a11y story fixes! Thanks for creating follow up tickets :)

@marcysutton marcysutton merged commit 5036747 into main Dec 4, 2025
15 checks passed
@marcysutton marcysutton deleted the modal-docs branch December 4, 2025 00:41
@codecov
Copy link

codecov bot commented Dec 4, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (c6b38e2) to head (9d29c92).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@     Coverage Diff      @@
##   main   #2875   +/-   ##
============================
============================

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c6b38e2...9d29c92. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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