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

Un-revert "Add loading prop for Button and IconButton (#3582)" #4485

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

Conversation

mperrotti
Copy link
Contributor

Brings back #3582

Copy link

changeset-bot bot commented Apr 10, 2024

🦋 Changeset detected

Latest commit: 4fce38a

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

This PR includes changesets to release 1 package
Name Type
@primer/react Minor

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

@mperrotti mperrotti changed the title Revert "Revert "Add loading prop for Button and IconButton (#3582)"" Un-revert "Add loading prop for Button and IconButton (#3582)" Apr 10, 2024
Copy link
Contributor

github-actions bot commented Apr 10, 2024

size-limit report 📦

Path Size
packages/react/dist/browser.esm.js 88.91 KB (+1.07% 🔺)
packages/react/dist/browser.umd.js 89.14 KB (+0.97% 🔺)

@github-actions github-actions bot temporarily deployed to storybook-preview-4485 April 10, 2024 15:44 Inactive
@siddharthkp siddharthkp added the no-breaking-changes: need to test This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm label Apr 10, 2024
@siddharthkp
Copy link
Member

siddharthkp commented Apr 10, 2024

Hi! There is another bug when aria-label is present, tried to address that in this PR (not merged): #4459

Should I copy those changes over here as well?

@mperrotti
Copy link
Contributor Author

@siddharthkp - yes, please copy those changes over as well

@siddharthkp
Copy link
Member

Sorry, while copying over my changes, I ran into a couple questions

On this line: https://github.com/primer/react/pull/4485/files#diff-515525e4a59d9a55e13c6c60155ec6782c78a026aae4c540c324cd8e11c83a48R102-R105,

aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state.

Looking at this comment, is this still true? It looks like we set aria-describedby not label aria-label or aria-labelledby 🤔

@mperrotti
Copy link
Contributor Author

@siddharthkp I'm not sure I understand your question because we set all three depending on the situation.

We set aria-label for IconButton (see Storybook example)

We set aria-labelledby for either of these cases:

  • loading prop is true
  • aria-labelledby prop has been passed

We set aria-describedby for either of these cases:

  • loading prop is true
  • aria-describedby prop has been passed

@siddharthkp
Copy link
Member

siddharthkp commented Apr 16, 2024

Sorry, bad choice of words from me. I'll try again

Looking at this block of code: https://github.com/primer/react/pull/4485/files#diff-515525e4a59d9a55e13c6c60155ec6782c78a026aae4c540c324cd8e11c83a48R102-R105:

// aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state.
// We only set it when the button is in a loading state because it will supercede the aria-label when the screen
// reader announces the button name.
aria-labelledby={loading ? `${uuid}-label` : ariaLabelledBy}

and wondering why/when accessible name becomes unset when the button is in a loading state?

I removed it that line and saw no changes which really confused me. I'm probably missing something very obvious here, thanks for your patience with me!

@mperrotti
Copy link
Contributor Author

Thanks @siddharthkp

I removed it that line and saw no changes which really confused me. I'm probably missing something very obvious here, thanks for your patience with me!

I had the same experience in the browser, but it caused the following test to fail:

 ● Button › should preserve the accessible button name when the button is in a loading state

    expect(element).toHaveAccessibleName()

    Expected element to have accessible name:
      content
    Received:

      248 |     const container = render(<Button loading>content</Button>)
      249 |
    > 250 |     expect(container.getByRole('button')).toHaveAccessibleName('content')
          |                                           ^
      251 |   })
      252 | })

@siddharthkp
Copy link
Member

I had the same experience in the browser, but it caused the following test to fail:

Oh that's rough! Ideally, I'd like to optimise it for the browser and fix/workaround the jest error. UNLESS, we also see similar jest errors in dotcom integration tests?

cc @joshblack @broccolinisoup @pksjce (nerd sniping 🤭) have you seen something like this before?

@TylerJDev
Copy link
Contributor

I removed it that line and saw no changes which really confused me.

It looks like when the button is in a loading state, the text is visually hidden via visibility: hidden. This means that it will be ignored in the accessibility tree and won't be used as the accessible name. Usage of aria-labelledby is valid on elements that use visibility: hidden which is why this works only when aria-labelledby is used.

I'm thinking that there are only a few options here, one being the current pattern using the aria-labelledby. We could also hide the text without using visibility: hidden, but I'm not sure if this is done anywhere in PRC currently.

// aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state.
// We only set it when the button is in a loading state because it will supercede the aria-label when the screen
// reader announces the button name.
aria-labelledby={loading ? `${uuid}-label` : ariaLabelledBy}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if we could add ariaLabelledBy to the first condition too?

(i.e. ${uuid}-label ${ariaLabelledBy} : ariaLabelledBy)

This allows instances that rely on aria-labelledby to remain covered, even if the button is in a loading state.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh I didn't realize we could have 2 values in aria-labelledby. That could work! I'll give it a try...

@mperrotti
Copy link
Contributor Author

mperrotti commented Apr 26, 2024

I'm thinking that there are only a few options here, one being the current pattern using the aria-labelledby. We could also hide the text without using visibility: hidden, but I'm not sure if this is done anywhere in PRC currently.

We have a component for that: https://github.com/primer/react/blob/main/packages/react/src/internal/components/VisuallyHidden.tsx

@mperrotti
Copy link
Contributor Author

@siddharthkp - do you think @TylerJDev 's suggestion will fix our problem?

@TylerJDev
Copy link
Contributor

@siddharthkp - do you think @TylerJDev 's suggestion will fix our problem?

I believe the problem would still persist here if there's no ariaLabelledBy being passed. I'd say utilizing aria-labelledby as you're doing now is definitely a way to go about it, while also adding the ariaLabelledBy prop to the first condition.

We have a component for that: https://github.com/primer/react/blob/main/packages/react/src/internal/components/VisuallyHidden.tsx

This would actually be a good alternative! We wouldn't need to reference the inner span anymore if we used this, and it should be visually equivalent to visibility: hidden. I might prefer this route, as we wouldn't need to handle aria-labelledby directly anymore.

Copy link
Contributor

@khiga8 khiga8 left a comment

Choose a reason for hiding this comment

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

Took a look because I am looking at an adjacent topic of buttons with dynamically updated labels! :)

return (
<>
<VisuallyHidden aria-live="polite">{!loading && success ? 'Export completed' : null}</VisuallyHidden>
<Button loading={loading} leadingVisual={DownloadIcon} onClick={onClick('error')}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
<Button loading={loading} leadingVisual={DownloadIcon} onClick={onClick('error')}>
<Button loading={loading} leadingVisual={DownloadIcon} onClick={onClick('success')}>

Should this be success? I noticed that the live region doesn't get updated with the Export completed announcement in the storybook success example.

It seems to be getting updated for the error example though!

)
}

export const LoadingStatusAnnouncementError = () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

In this example, the failure state is communicated to assistive technologies via announcement, but there's no visual indication that anything failed.

Do we have guidance around communicating errors visually? If so, should this example include that?


return (
<>
<VisuallyHidden aria-live="polite">{!loading && error ? 'Export failed' : null}</VisuallyHidden>
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the announcement utility components be used in these examples instead, or are they only recommended for use internally? (cc: @joshblack)

Suggested change
<VisuallyHidden aria-live="polite">{!loading && error ? 'Export failed' : null}</VisuallyHidden>
<VisuallyHidden><Status>{!loading && error ? 'Export failed' : null}</Status></VisuallyHidden>


export default meta

export const LoadingStatusAnnouncementSuccessful = () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

In these examples, when the loading state is activated, the focus gets lost and removed from the button. I believe this is a 2.4.3 issue, and may result in some screen reader users ending up at the top of the page. Could we avoid focus loss?

@lindseywild
Copy link
Contributor

@mperrotti is there anything the a11y v-team can help with to get this PR along the finish line?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-breaking-changes: need to test This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants