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

fix(modal): ariaLabel and role are inherited when set via htmlAttributes #29099

Merged
merged 4 commits into from
Feb 29, 2024

Conversation

liamdebeasi
Copy link
Contributor

@liamdebeasi liamdebeasi commented Feb 28, 2024

Issue number: Internal


What is the current behavior?

Modal inherits aria-label and role to an element inside of its Shadow DOM. However, this only works if developers set the attributes on the host element directly. Setting the attributes via the htmlAttributes property causes the attributes to be set on the host and not inherited.

What is the new behavior?

  • aria-label and role are inherited even when set using htmlAttributes.

Does this introduce a breaking change?

  • Yes
  • No

Other information

Dev build: 7.7.4-dev.11709154993.1b49c313

@github-actions github-actions bot added the package: core @ionic/core package label Feb 28, 2024

import { Modal } from '../../modal';

describe('modal: a11y', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to add tests for all of the inherited roles, and I also wanted to test the htmlAttributes behavior that I added in this PR. As a result, I decided to remove this test in favor of more generic attribute tests.

Comment on lines +360 to +362
* We could alternatively move this to componentDidLoad to simplify the work
* here, but we'd then need to make inheritedAttributes a State variable,
* thus causing another render to always happen after the first render.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Open to other ideas since the code is a bit gnarly. I did consider using the Watch callback for attributes, but I realized that wouldn't help us since Watch callbacks do not get run when the component is loaded.

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 okay with this approach. There's probably a cleaner way of doing it with some clever use of Object.keys()/filter()/reduce(), but the general strategy works for me. I came up with this after staring at it for 20 minutes; might be slightly easier to grok and it cuts a layer of nesting.

if (htmlAttributes !== undefined) {
  const htmlAttributesToInherit = Object.keys(htmlAttributes).filter(attr => attr in attributesToInherit);
  htmlAttributesToInherit.forEach((attribute) => {
    this.inheritedAttributes = {
      ...this.inheritedAttributes,
      [attribute]: htmlAttributes[attribute],
    };

    delete htmlAttributes[attribute];
  });
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I ended up just sticking with the approach in the PR. The Object.keys approach has some scalability concerns since worst case you'll need to iterate through htmlAttributes 3 times. (Object.keys, then filtering the array, then iterating through the result). We only inherit 2 attributes, so the performance impact right now is negligible. But if we were to increase the number of attributes inherited this would become more of a problem.

@liamdebeasi liamdebeasi changed the title Fw 5899 fix(modal): ariaLabel and role are inherited when set via htmlAttributes Feb 28, 2024
@liamdebeasi liamdebeasi marked this pull request as ready for review February 28, 2024 21:33
@liamdebeasi liamdebeasi requested a review from a team as a code owner February 28, 2024 21:33
@liamdebeasi liamdebeasi requested review from averyjohnston and removed request for a team February 28, 2024 21:33
Comment on lines +360 to +362
* We could alternatively move this to componentDidLoad to simplify the work
* here, but we'd then need to make inheritedAttributes a State variable,
* thus causing another render to always happen after the first render.
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 okay with this approach. There's probably a cleaner way of doing it with some clever use of Object.keys()/filter()/reduce(), but the general strategy works for me. I came up with this after staring at it for 20 minutes; might be slightly easier to grok and it cuts a layer of nesting.

if (htmlAttributes !== undefined) {
  const htmlAttributesToInherit = Object.keys(htmlAttributes).filter(attr => attr in attributesToInherit);
  htmlAttributesToInherit.forEach((attribute) => {
    this.inheritedAttributes = {
      ...this.inheritedAttributes,
      [attribute]: htmlAttributes[attribute],
    };

    delete htmlAttributes[attribute];
  });
}

@liamdebeasi liamdebeasi added this pull request to the merge queue Feb 29, 2024
Merged via the queue into main with commit de13633 Feb 29, 2024
46 checks passed
@liamdebeasi liamdebeasi deleted the FW-5899 branch February 29, 2024 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: core @ionic/core package
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants