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

Add modal glossary of payment methods #181

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

Conversation

oyamauchi
Copy link
Member

@oyamauchi oyamauchi commented Jul 22, 2024

Description

There's a lot going on here, so here's the high-level tour:

  • The glossary modal itself looks (I think) exactly as designed. I've
    made a few edits to the copy compared to what's in the Figma; I've
    put comments in the Figma to explain why.

  • The accordion sections use Headless UI's Disclosure component.

  • Most of the logic of displaying a modal dialog is hand-written,
    though I added third-party packages to trap focus within it and stop
    the body from scrolling while it's up.

    I did try using Headless UI's Dialog component, which does all
    that out of the box, but (like the rest of Headless!) it doesn't account
    for shadow DOMs. It renders the dialog at the root of document,
    where it does not get any of the shadow DOM's styling; there seems
    to be no way to change this.

  • The entire incentive-type chip is now a button. (The alternative was
    to make only the icon the button, which makes for an uncomfortably
    small click target.) This required a bit of refactoring of the
    incentive card component.

Accessibility

  • Keyboard navigation:

    • When you activate one of the chip buttons, focus automatically
      goes to the section header of the appropriate section. (The entire
      header is an expand/collapse button, not just the circled
      chevron.)

    • The modal traps focus while it's up.

    • Hitting Escape while the modal is up will dismiss it.

    • When the modal closes, focus returns to the chip button that
      caused it to open.

  • Screenreader experience: I think it's OK? I am not an expert screen
    reader user by any means. It's possible a few more things could use
    ARIA roles.

    One judgment call I made is to aria-label the question icon in the
    chips as "show glossary". When a chip is focused, the reader says
    "Tax credit show glossary, button". It seemed good to have a clue as
    to what will happen if you click the button?

Next steps

If this all seems suitable, I'll request translations.

Test Plan

  • Look at the component on all widths, in several browsers (tried
    Chrome, Firefox, Safari, MobileSafari). Make sure the section
    corresponding to the incentive type you clicked on is open as soon
    as the modal appears, and no others are open. Click on others to
    open and close. Open all the sections and make sure the scrolling is
    correct.

  • Make sure the modal is dismissible by clicking away from the body,
    clicking the X button, or hitting Escape.

  • Scroll-wheel with the cursor away from the modal body, and make sure
    the document doesn't scroll underneath.

  • Navigate with keyboard: tab to the incentive-type chip and hit
    Enter. Make sure focus is immediately on the right section
    header. Tab and shift-tab and make sure focus is trapped within the
    modal. Hit Esc, or "enter" on the X button, and make sure focus is
    back on the original chip.

  • Do all of the above with VoiceOver on.

Copy link

vercel bot commented Jul 22, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
embed-rewiringamerica-org ✅ Ready (Inspect) Visit Preview Sep 9, 2024 10:37pm

/>
</span>
</Disclosure.Button>
<Disclosure.Panel className="flex flex-col gap-4">
Copy link
Contributor

@matelau matelau Jul 23, 2024

Choose a reason for hiding this comment

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

Re: VoiceOver - Should the focus go to the button or go to the panel with the content? I'm not the best with VoiceOver, but I have used it before and I was having some issues getting VoiceOver to read the content as it was just iterating through the buttons and not making it to the glossary content.

I think there is some controversy over setting tabindex to do this, but that is possibly one way? https://webaim.org/techniques/keyboard/tabindex

But here is the applicable WCAG standard https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html

Copy link
Member Author

Choose a reason for hiding this comment

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

It works for me in my main browser (Brave; Chromium-based). But I wouldn't be surprised if other browsers behave differently; I'm consistently surprised at how much variety there is in how browsers build the accessibility tree.

Also, the content is just plain <p>s with text inside; I can't imagine any browser would ignore those?

Copy link
Member

@veekas veekas left a comment

Choose a reason for hiding this comment

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

voice over seemed good to me

src/glossary.tsx Outdated
<CircledChevron
w={40}
h={40}
fillClass="fill-[#ebebeb] group-data-open:fill-color-action-primary"
Copy link
Member

Choose a reason for hiding this comment

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

nit, it's slightly different, but can we use grey-200 here instead? It has a Delta E ratio (i.e. color difference) of 2, which is only barely perceptible

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure -- I just took ebebeb from the designs; I don't know why Emiola went outside the design system colors though.

src/glossary.tsx Outdated
Comment on lines 228 to 229
// Prevent clicks on the body from closing the modal
onClick={e => e.stopPropagation()}
Copy link
Member

Choose a reason for hiding this comment

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

the "body" as in the rest of the page under the modal? if so, it appears to close the modal on click.

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 meant the body of the modal itself -- the white-background div. Only clicks on the blurry background should close the modal. I can clarify that.

aria-label={msg('Show glossary')}
w={10}
h={10}
opacity={1.0}
Copy link
Member

Choose a reason for hiding this comment

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

probably redundant, unless there's some inheritance going on that I'm missing

Copy link
Member Author

Choose a reason for hiding this comment

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

It's because the same QuestionIcon component is used for the tooltip icons in the form, where it has to be 50% opacity. I guess I should make it so 100% is the default, though, and the usage in the form has to specify 50% explicitly. I'll change that.

Comment on lines +314 to +262
<button
type="button"
Copy link
Member

Choose a reason for hiding this comment

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

should we use the Button component? either way, I don't think we need the type attribute here

Copy link
Member Author

Choose a reason for hiding this comment

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

There's no Button component in this codebase -- it doesn't use a library of styled components at all. There are a couple of reusable things in src/buttons.tsx, but none of those are applicable here.

Also, the default <button> type is submit, which is not what we want here. (Although this button isn't within a form, so submit and button would have the same behavior anyway, but I'm just in the habit of writing type=button.)

## Description

There's a lot going on here, so here's the high-level tour:

- The glossary modal itself looks (I think) exactly as designed. I've
  made a few edits to the copy compared to what's in the Figma; I've
  put comments in the Figma to explain why.

- Most of the logic of displaying a modal dialog is hand-written,
  though I added third-party packages to trap focus within it and stop
  the body from scrolling while it's up.

  I did try using Headless UI's `Dialog` component, which does all
  that out of the box, but (like the rest of Headless!) it's unusable
  with shadow DOM. It renders the dialog at the root of `document`,
  where it does not get any of the shadow DOM's styling; there seems
  to be no way to change this.

- The entire incentive-type chip is now a button. (The alternative was
  to make only the icon the button, which makes for an uncomfortably
  small click target.) This required a bit of refactoring of the
  incentive card component.

### Accessibility

- Keyboard navigation:

  - When you activate one of the chip buttons, focus automatically
    goes to the section header of the appropriate section. (The entire
    header is an expand/collapse button, not just the circled
    chevron.)

  - The modal traps focus while it's up.

  - Hitting Escape while the modal is up will dismiss it.

  - When the modal closes, focus returns to the chip button that
    caused it to open.

- Screenreader experience: I think it's OK? I am not an expert screen
  reader user by any means. It's possible a few more things could use
  ARIA roles.

  One judgment call I made is to aria-label the question icon in the
  chips as "show glossary". When a chip is focused, the reader says
  "Tax credit show glossary, button". It seemed good to have a clue as
  to what will happen if you click the button?

### Next steps

If this all seems suitable, I'll request translations.

## Test Plan

- Look at the component on all widths, in several browsers (tried
  Chrome, Firefox, Safari, MobileSafari). Make sure the section
  corresponding to the incentive type you clicked on is open as soon
  as the modal appears, and no others are open. Click on others to
  open and close. Open all the sections and make sure the scrolling is
  correct.

- Make sure the modal is dismissible by clicking away from the body,
  clicking the X button, or hitting Escape.

- Scroll-wheel with the cursor away from the modal body, and make sure
  the document doesn't scroll underneath.

- Navigate with keyboard: tab to the incentive-type chip and hit
  Enter. Make sure focus is immediately on the right section
  header. Tab and shift-tab and make sure focus is trapped within the
  modal. Hit Esc, or "enter" on the X button, and make sure focus is
  back on the original chip.

- Do all of the above with VoiceOver on.
Copy link
Member Author

@oyamauchi oyamauchi left a comment

Choose a reason for hiding this comment

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

Translations are requested, and I'll make a few updates from the feedback.

src/glossary.tsx Outdated
<CircledChevron
w={40}
h={40}
fillClass="fill-[#ebebeb] group-data-open:fill-color-action-primary"
Copy link
Member Author

Choose a reason for hiding this comment

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

Sure -- I just took ebebeb from the designs; I don't know why Emiola went outside the design system colors though.

src/glossary.tsx Outdated
Comment on lines 228 to 229
// Prevent clicks on the body from closing the modal
onClick={e => e.stopPropagation()}
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 meant the body of the modal itself -- the white-background div. Only clicks on the blurry background should close the modal. I can clarify that.

aria-label={msg('Show glossary')}
w={10}
h={10}
opacity={1.0}
Copy link
Member Author

Choose a reason for hiding this comment

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

It's because the same QuestionIcon component is used for the tooltip icons in the form, where it has to be 50% opacity. I guess I should make it so 100% is the default, though, and the usage in the form has to specify 50% explicitly. I'll change that.

Comment on lines +314 to +262
<button
type="button"
Copy link
Member Author

Choose a reason for hiding this comment

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

There's no Button component in this codebase -- it doesn't use a library of styled components at all. There are a couple of reusable things in src/buttons.tsx, but none of those are applicable here.

Also, the default <button> type is submit, which is not what we want here. (Although this button isn't within a form, so submit and button would have the same behavior anyway, but I'm just in the habit of writing type=button.)

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.

3 participants