Skip to content

feat(unity-react-core): modal auto focus and disabled tab to content … - #1768

Open
spaceperson wants to merge 42 commits into
devfrom
uds02-2211
Open

feat(unity-react-core): modal auto focus and disabled tab to content …#1768
spaceperson wants to merge 42 commits into
devfrom
uds02-2211

Conversation

@spaceperson

Copy link
Copy Markdown
Contributor

…outside the modal

Description

Checklist

  • Tests pass for relevant code changes

Important Reminders

Links

@spaceperson
spaceperson requested a review from a team as a code owner August 5, 2026 17:27
@asu-jenkins-devops

Copy link
Copy Markdown
Collaborator

</GaEventWrapper>
<h1>{modalTitle}</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Content should be a prop

* @typedef {Object} ButtonIconOnlyProps
* @property {Array.<string>} icon
* @property {string} [color]
* @property {boolean} [autoFocus]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this always be true?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh the name confused me. is this variable for automatically opening the modal on page load? Can we pick a different variable name? variable name should describe if true the modal will be open when it loads

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's an html value for automatically updating the focus to activate the button when the modal opens. I left it as an option, but it didn't work when I tried it. I assumed it was because another element was taking priority. I didn't see the harm in leaving it as an option, but we could remove it.

https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/autofocus
JSX uses camel case instead of the lowercase autofocus value.


useEffect(() => {
if (!openState) return;
if (!openState) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@davidornelas11 are we mixing our react components with js inside bootstrap-theme (it technically loses react "coolness" but makes the functionality consistant)

If we use react functionality,

  • make sure the bootstrap JS script does not conflict.
  • useRef will be a better solution to target the element.

@@ -1,22 +1,101 @@
import { EventHandler } from "./bootstrap-helper";

function openModal() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should the modal close if a user clicks the backdrop? I thought this was a standard behavior?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I thought that feature missing was odd as well but wasn't sure if there was a reason we didn't have that feature. I'll implement that with the next update.

// const mainContentChildren = mainContent.children;
// let mainContentChildrenArray = Array.from(mainContentChildren);
// for (let i = 0; i < mainContentChildrenArray.length; i++) {
// mainContentChildrenArray[i].setAttribute("inert", "");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clean up code we aren't keeping

closeModal();
});

document?.addEventListener("keydown", function (event) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

remove this event when the modal is not open

}

if (e.shiftKey) {
// if shift key pressed for shift + tab combination

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets let the native tab event do its thing. you can create a focus trap

import { EventHandler } from "./bootstrap-helper";

function initModals() {
  const modal = document.getElementById("uds-modal");
  const openModalButton = document.getElementById("openModalButton");
  const closeModalButton = document.getElementById("closeModalButton");
  const firstFocusable = modal.querySelector(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );

  let previousFocus = null;
  function focusTrap(e) {
    // If relatedTarget is outside, move focus back inside
    if (!modal.contains(e.relatedTarget)) {
      firstFocusable?.focus();
    }
  }

  function openModal() {
    // When opening: save current focus and move into modal
    previousFocus = document.activeElement;
    modal.classList.add("open");
    // attach event listeners to trap focus and close modal
    modal.addEventListener("focusout", focusTrap);
    modal.addEventListener("click", closeModal, true);
    document.addEventListener("keydown", closeModal);
    // Focus the first interactive element inside (or body if none)
    firstFocusable?.focus();
  }

  function closeModal({ type, target, key } = {}) {
    if (
      // escape key pressed
      (type === "keydown" && key === "Escape") ||
      // click outside modal
      (type === "click" && target === modal) ||
      // click on close button
      (type === "click" && target === closeModalButton)
    ) {
      modal.classList.remove("open");
      modal.removeEventListener("focusout", focusTrap);
      modal.removeEventListener("click", closeModal, true);
      document.removeEventListener("keydown", closeModal);
      // When closing: restore original focus
      previousFocus?.focus();
    }
  }
  openModalButton.addEventListener("click", openModal);
}

EventHandler.on(window, "load.uds.modals", initModals);

export { initModals };

spaceperson and others added 21 commits August 11, 2026 17:56
The Web Directory profile card rendered the person's work title in an
h4, causing a skipped heading level on consuming sites where the card
name is not a heading (accessibility issue).

- ProfileCard (app-webdir-ui) and PersonProfile (unity-react-core) now
  render the title as p.person-profession-title > strong
- unity-bootstrap-theme styles the new class identically to the old h4
  (1rem, 700 weight, 1.625rem line-height, 2-line clamp); h4 selectors
  kept for backward compatibility with published consumers
- person-profile Storybook template updated to the new markup
# [@asu/app-webdir-ui-v5.0.16](https://github.com/asu/asu-unity-stack/compare/@asu/app-webdir-ui-v5.0.15...@asu/app-webdir-ui-v5.0.16) (2026-07-25)

### Bug Fixes

* **app-webdir-ui:** fix alpha scrolling ([c7c8944](c7c8944))
…eact-dom/server

- Restore the .scroll-control-prev/-next and carousel-control-*-icon
  styles into NavControls.styles.js (co-located with the component
  instead of unity-bootstrap-theme). PR #1698's TabbedPanels redesign
  removed this CSS assuming it was dead code from the old carousel-based
  tabs, but NavControls is still used standalone by app-webdir-ui's
  Filter component ("Filter by Last Initial"), which regressed to
  unstyled buttons as a result.
- Split getBootstrapHTML (react-dom/server, Storybook/dev-tooling only)
  out of useBaseSpecificFramework.js into its own file. Every component
  imports useBaseSpecificFramework at runtime, so bundling
  react-dom/server there was pulling server-rendering internals
  (MessageChannel, TextEncoder, etc.) into every consumer's published
  dist for no runtime benefit, and broke jsdom-based tests in
  app-webdir-ui.
…-react-core dependency ranges

Both were pinned to ^1.x ranges that no longer match the workspace's
current major versions (unity-bootstrap-theme 2.x, unity-react-core 2.x),
causing yarn to resolve a stale published copy from the registry instead
of symlinking the local workspace package.
… range

Was pinned to ^1.0.0, which no longer matches the workspace's current
2.x version, causing yarn to resolve a stale published copy from the
registry instead of symlinking the local workspace package.
…ange

Was pinned to ^1.0.0, which no longer matches the workspace's current
2.x version, causing yarn to resolve a stale published copy from the
registry instead of symlinking the local workspace package.
… range

Was pinned to ^1.20, which no longer matches the workspace's current
2.x version, causing yarn to resolve a stale published copy from the
registry instead of symlinking the local workspace package.
… range

Was pinned to ^1.0.0, which no longer matches the workspace's current
2.x version, causing yarn to resolve a stale published copy from the
registry instead of symlinking the local workspace package.
# [@asu/unity-react-core-v2.1.1](https://github.com/ASU/asu-unity-stack/compare/@asu/unity-react-core-v2.1.0...@asu/unity-react-core-v2.1.1) (2026-07-28)

### Bug Fixes

* **unity-react-core:** restore nav-control styles and stop bundling react-dom/server ([cb41952](cb41952))
# [@asu/app-degree-pages-v3.2.3](https://github.com/asu/asu-unity-stack/compare/@asu/app-degree-pages-v3.2.2...@asu/app-degree-pages-v3.2.3) (2026-07-28)

### Bug Fixes

* **app-degree-pages:** correct stale @asu/unity-react-core dependency range ([81ce102](81ce102))
# [@asu/app-rfi-v3.10.3](https://github.com/asu/asu-unity-stack/compare/@asu/app-rfi-v3.10.2...@asu/app-rfi-v3.10.3) (2026-07-28)

### Bug Fixes

* **app-rfi:** correct stale @asu/unity-bootstrap-theme and @asu/unity-react-core dependency ranges ([7214d47](7214d47))
# [@asu/app-webdir-ui-v5.0.17](https://github.com/asu/asu-unity-stack/compare/@asu/app-webdir-ui-v5.0.16...@asu/app-webdir-ui-v5.0.17) (2026-07-28)

### Bug Fixes

* **app-webdir-ui:** fix nav controls and anon image for webdir ([0e68046](0e68046))
# [@asu/component-events-v3.2.1](https://github.com/asu/asu-unity-stack/compare/@asu/component-events-v3.2.0...@asu/component-events-v3.2.1) (2026-07-28)

### Bug Fixes

* **component-events:** correct stale @asu/unity-react-core dependency range ([8b66069](8b66069))
# [@asu/component-news-v4.2.2](https://github.com/asu/asu-unity-stack/compare/@asu/component-news-v4.2.1...@asu/component-news-v4.2.2) (2026-07-28)

### Bug Fixes

* **component-news:** correct stale @asu/unity-react-core dependency range ([d5f3869](d5f3869))
davidornelas11 and others added 20 commits August 18, 2026 10:59
# [@asu/unity-bootstrap-theme-v2.2.0](https://github.com/ASU/asu-unity-stack/compare/@asu/unity-bootstrap-theme-v2.1.1...@asu/unity-bootstrap-theme-v2.2.0) (2026-07-29)

### Bug Fixes

* **unity-bootstrap-theme:** fix modal close button focus style issue ([c288469](c288469))

### Features

* modal accessibility and escape key features for unity react and bootstrap ([04bdeea](04bdeea))

### Performance Improvements

* **unity-react-core:** useEffect update for React js async key listener handling ([b25ab85](b25ab85))
# [@asu/unity-react-core-v2.2.0](https://github.com/ASU/asu-unity-stack/compare/@asu/unity-react-core-v2.1.1...@asu/unity-react-core-v2.2.0) (2026-07-29)

### Features

* modal accessibility and escape key features for unity react and bootstrap ([04bdeea](04bdeea))
* **unity-react-core:** aria-label update ([eeaebef](eeaebef))

### Performance Improvements

* **unity-react-core:** useEffect update for React js async key listener handling ([b25ab85](b25ab85))
# [@asu/unity-bootstrap-theme-v2.2.1](https://github.com/ASU/asu-unity-stack/compare/@asu/unity-bootstrap-theme-v2.2.0...@asu/unity-bootstrap-theme-v2.2.1) (2026-07-30)

### Bug Fixes

* **unity-bootstrap-theme:** allow ordered lists to be reversed ([d33c05e](d33c05e))
# [@asu/component-header-footer-v1.4.6](https://github.com/asu/asu-unity-stack/compare/@asu/component-header-footer-v1.4.5...@asu/component-header-footer-v1.4.6) (2026-07-31)

### Bug Fixes

* **component-header-footer:** fixed large headers not wrapping on smaller screens ([ed046e1](ed046e1))
# [@asu/unity-bootstrap-theme-v2.2.2](https://github.com/ASU/asu-unity-stack/compare/@asu/unity-bootstrap-theme-v2.2.1...@asu/unity-bootstrap-theme-v2.2.2) (2026-08-03)

### Bug Fixes

* **unity-bootstrap-theme:** add unity defgault focus ring to hover card ([441a16a](441a16a))
* **unity-bootstrap-theme:** tabindex update for hover cards ([1bd6834](1bd6834))
Bumps [undici](https://github.com/nodejs/undici) from 6.27.0 to 6.28.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](nodejs/undici@v6.27.0...v6.28.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.28.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
# [@asu/unity-bootstrap-theme-v2.2.3](https://github.com/ASU/asu-unity-stack/compare/@asu/unity-bootstrap-theme-v2.2.2...@asu/unity-bootstrap-theme-v2.2.3) (2026-08-06)

### Bug Fixes

* **app-webdir-ui:** render profile card title as bold text instead of h4 ([f7fb027](f7fb027))
# [@asu/unity-react-core-v2.2.1](https://github.com/ASU/asu-unity-stack/compare/@asu/unity-react-core-v2.2.0...@asu/unity-react-core-v2.2.1) (2026-08-06)

### Bug Fixes

* **app-webdir-ui:** render profile card title as bold text instead of h4 ([f7fb027](f7fb027))
# [@asu/app-webdir-ui-v5.0.18](https://github.com/asu/asu-unity-stack/compare/@asu/app-webdir-ui-v5.0.17...@asu/app-webdir-ui-v5.0.18) (2026-08-07)

### Bug Fixes

* **app-webdir-ui:** render profile card title as bold text instead of h4 ([f7fb027](f7fb027))
# [@asu/app-degree-pages-v3.2.4](https://github.com/asu/asu-unity-stack/compare/@asu/app-degree-pages-v3.2.3...@asu/app-degree-pages-v3.2.4) (2026-08-07)

### Bug Fixes

* **app-degree-pages:** delete degree detail page component ([83e8992](83e8992))
* **app-degree-pages:** fix relative path in Breadcrumbs import ([83338bf](83338bf))
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.

9 participants