Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RAC Pending Button #6435

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open

RAC Pending Button #6435

wants to merge 12 commits into from

Conversation

snowystinger
Copy link
Member

@snowystinger snowystinger commented May 23, 2024

Closes

I've opted to re-implement it in RAC as opposed to pushing it down into the hooks because the hacks we use to work around AT require a bunch of dom nodes, which either leads to a lot of oddly named collections of element props being returned by the useButton hook, or a new hook which handles it. Either way results in API additions which would be not great to maintain.

Reminder, in Safari, you must use VO+space to click the button in order to get the announcement.

API questions:

Do we want to give renderProps to the pending state?

Default pending state? or make pending props an object such that we can require the pending ReactNode if isPending is set true.

Names of props, not sure what to call renderPendingState, I structured it after renderEmptyState.

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

🧢 Your Project:

@rspbot
Copy link

rspbot commented May 23, 2024

packages/react-aria-components/src/Button.tsx Outdated Show resolved Hide resolved
packages/react-aria-components/src/Button.tsx Outdated Show resolved Hide resolved
packages/react-aria-components/src/Button.tsx Outdated Show resolved Hide resolved
@rspbot
Copy link

rspbot commented Jun 11, 2024

@rspbot
Copy link

rspbot commented Jun 11, 2024

@rspbot
Copy link

rspbot commented Jun 11, 2024

packages/react-aria-components/package.json Outdated Show resolved Hide resolved
/**
* What to render as children while pending state is true.
*/
renderPendingState?: (props: ButtonRenderProps) => ReactNode
Copy link
Member

Choose a reason for hiding this comment

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

As per your questions in the description:
I think this naming and passing in the render props is fine. No need to set a default pending state renderer too IMO, we can just make that the user's responsibility IMO.

# Conflicts:
#	packages/react-aria-components/package.json
@rspbot
Copy link

rspbot commented Jun 23, 2024

@rspbot
Copy link

rspbot commented Jun 23, 2024

Comment on lines +157 to +162
<div
style={{display: 'contents'}}
id={containerId}
aria-atomic>
{renderProps.children}
</div>
Copy link

Choose a reason for hiding this comment

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

As a user of RAC I'm a bit concerned about the overhead of 1 additional HTML element within each button. No matter if isPending is ever used or not. Buttons are a very frequently used component and it should be as slim as possible IMO.

Copy link
Member Author

Choose a reason for hiding this comment

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

What are you worried about with the addition of one more HTML element? Is there a concrete issue? Buttons are already not what I would consider slim, see this three part blog series on building a button https://react-spectrum.adobe.com/blog/building-a-button-part-1.html

I'd love not to need these extra elements, but I haven't found a good way to handle the announcements without it so far.

Theoretically, buttons should just re-announce when you have focus on them and the contents change. However, this isn't true in practice. https://a11ysupport.io/tests/tech__html__button-name-change and even the ones that say they have support have different kinds of support.

When the button enters the pending state, we want that to be the first thing read. For an element which can appear and disappear, I think it makes more sense to keep it as the second sibling though so it doesn't push the original label out of the way if someone wants to keep the original label visible.
Someone could still visually change that with flex order, however, I didn't want to impose that on all buttons unexpectedly.

In order to get everything announced in the right order without double announcing, we use aria-atomic so the screen reader doesn't read off anything past the content except what we wish by joining together aria-labelledby.

We'll keep thinking on it and thanks for the feedback.

Copy link

Choose a reason for hiding this comment

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

I just remember that you should keep the amount of DOM nodes as low as possible. I think that's especially important in such a base building block like a component library/design system so you have room on application-level.

@rspbot
Copy link

rspbot commented Jun 30, 2024

@rspbot
Copy link

rspbot commented Jun 30, 2024

## API Changes

unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any', access: 'private' }
unknown top level export { type: 'any', access: 'private' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'identifier', name: 'Column' }
unknown top level export { type: 'identifier', name: 'Column' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants