Skip to content

va-maintenance-banner: Prevent additional slot from rendering in light DOM#1988

Merged
RyanMunsch merged 10 commits intomainfrom
4649-maintenance-banner-announcement
Feb 24, 2026
Merged

va-maintenance-banner: Prevent additional slot from rendering in light DOM#1988
RyanMunsch merged 10 commits intomainfrom
4649-maintenance-banner-announcement

Conversation

@RyanMunsch
Copy link
Copy Markdown
Contributor

@RyanMunsch RyanMunsch commented Feb 12, 2026

Chromatic

https://4649-maintenance-banner-announcement--65a6e2ed2314f7b8f98609d8.chromatic.com

Description

This pull request refactors the va-maintenance-banner web component to improve its logic for rendering and accessibility. The main focus is on determining when and how the maintenance banner should be displayed, ensuring unused content is removed for screen readers, and simplifying conditional rendering. Additionally, related test cases are updated to match the new logic.

Component logic and rendering improvements:

  • Added a componentWillLoad lifecycle method to centralize logic for:
    • Determining if the banner should render based on dates and local storage.
    • Setting a flag (isWarning) to distinguish between warning and error states.
    • Removing the unused slot (warn-content or maintenance-content) from the DOM for accessibility. [1] [2]
  • Refactored the render method to:
    • Use the new preventRender flag to decide whether to render the banner.
    • Simplify and clarify the logic for which slot content to display based on isWarning. [1] [2] [3]

Accessibility improvements:

  • Ensured that only the relevant slot (warn-content or maintenance-content) is present in the DOM, preventing confusion for screen readers and assistive technologies.

Test updates:

  • Updated end-to-end tests to match the new slot removal logic, ensuring only the appropriate content is present for each banner state. [1] [2] [3]

Code cleanup:

  • Adjusted imports to include the @Element decorator for DOM manipulation.

Related tickets and links

Closes department-of-veterans-affairs/vets-design-system-documentation#4649

Screenshots

Before

maintenance-banner-prod

After

maiintenance-banner-4649

Testing and review

Approvals

See the QA Checklists section below for suggested approvals. Use your best judgment if additional reviews are needed. When in doubt, request a review.

Approval groups

Add approval groups to the PR as needed:

QA checklists

Use the QA checklists below as guides, not rules. Not all checklists will apply to every PR but there could be some overlap.

In all scenarios, changes should be fully tested by the author and verified by the reviewer(s); functionality, responsiveness, etc.

✨ New Component Added
  • The PR has the minor label
  • The component matches the Figma designs.
  • All properties, custom events, and utility functions have e2e and/or unit tests
  • A new Storybook page has been added for the component
  • Tested in all VA breakpoints.
  • Chromatic UI Tests have run and snapshot changes have been accepted by the design reviewer
  • Tested in vets-website using Verdaccio
  • Engineering has approved the PR
  • Design has approved the PR
  • Accessibility has approved the PR
🌱 New Component Variation Added
  • The PR has the minor label
  • The variation matches its Figma design.
  • Any new properties, custom events, or utility functions have e2e and/or unit tests
  • A new story has been added to the component's existing Storybook page
  • Any Chromatic UI snapshot changes have been accepted by a design reviewer
  • Tested in vets-website using Verdaccio
  • Engineering has approved the PR
  • Design has approved the PR
🐞 Component Fix
  • The PR has the patch label
  • Any new properties, custom events, or utility functions have e2e and/or unit tests
  • Any markup changes are evaluated for impact on vets-website.
    • Will any vets-website tests fail from the change?
  • Any Chromatic UI snapshot changes have been reviewed and approved by a designer if necessary
  • Engineering has approved the PR
♿️ Component Fix - Accessibility
  • The PR has the patch label
  • Any new properties, custom events, or utility functions have e2e and/or unit tests
  • Any Chromatic UI snapshot changes have been reviewed and approved by a designer if necessary
  • Engineering has approved the PR
  • Accessibility has approved the PR
🚨 Component Fix - Breaking API Change
  • The PR has the major label
  • vets-website and content-build have been evaluated to determine the impact of the breaking change
  • Any new properties, custom events, or utility functions have e2e and/or unit tests
  • Any Chromatic UI snapshot changes have been reviewed and approved by a designer if necessary
  • Tested in vets-website using Verdaccio
  • Engineering has approved the PR
🔧 Component Update - Non-Breaking API Change
  • The PR has the minor label
  • Any new properties, custom events, or utility functions have e2e and/or unit tests
  • Any Chromatic UI snapshot changes have been reviewed and approved by a designer if necessary
  • Engineering has approved the PR
📖 Storybook Update
  • The PR has the ignore-for-release label
  • Any Chromatic UI snapshot changes have been reviewed and approved by a designer if necessary
  • Engineering has approved the PR
🎨 CSS-Library Update
  • The PR has the css-library label
  • vets-website and content-build have been checked to determine the impact of any breaking changes
  • Engineering has approved the PR

Also refactor approach to move logic out of component's render method.
@RyanMunsch RyanMunsch added the patch Patch change in semantic versioning label Feb 12, 2026
@RyanMunsch RyanMunsch marked this pull request as ready for review February 12, 2026 15:23
@RyanMunsch RyanMunsch requested a review from a team as a code owner February 12, 2026 15:23
@RyanMunsch RyanMunsch requested review from a team February 12, 2026 15:39
@jamigibbs jamigibbs requested a review from Copilot February 13, 2026 14:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request refactors the va-maintenance-banner web component to improve its rendering logic, code organization, and accessibility. The component displays maintenance or warning banners on VA.gov based on date/time conditions and user interactions.

Changes:

  • Introduced componentWillLoad lifecycle method to centralize banner display logic, determine warning vs error state, and remove unused slots for accessibility
  • Refactored the render method to use cleaner conditional logic with pre-computed flags instead of nested conditions
  • Updated e2e tests to reflect that only the active slot remains in the light DOM

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
packages/web-components/src/components/va-maintenance-banner/va-maintenance-banner.tsx Added componentWillLoad method for early logic execution, added isWarning and preventRender flags, implemented slot removal for accessibility, and refactored render method for clearer conditional logic
packages/web-components/src/components/va-maintenance-banner/test/va-maintenance-banner.e2e.ts Updated test expectations to verify only the appropriate slot (warn-content or maintenance-content) remains in the light DOM based on banner state

Comment on lines +117 to +123
if (
isDateBefore(now, new Date(upcomingWarnStartDateTime)) ||
isDateAfter(now, new Date(maintenanceEndDateTime)) ||
window.localStorage.getItem('MAINTENANCE_BANNER') === bannerId
) {
this.preventRender = true;
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The refactored render method improves code readability by removing the nested conditional check for localStorage. However, there's now a subtle behavior change: in the old code, the localStorage check was done at render time (which happens after componentWillLoad), but now it's done in componentWillLoad. If the component is constructed and componentWillLoad runs, but the user dismisses the banner via some other mechanism before render happens, this could lead to inconsistent state. While this is a very unlikely edge case, it's worth noting the timing difference.

Copilot uses AI. Check for mistakes.
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.

For @department-of-veterans-affairs/platform-design-system-fe, I'm not sure that this is actually an issue. I was testing setting/removing that banner ID value from local storage in the Chrome devtools console and it has the same behavior here on the Chromatic deploy that it does on production.

Comment on lines 61 to 66
<div slot="maintenance-content">
We’re working on VA.gov right now. If you have trouble signing in or using tools, check back after we’re finished. Thank you for your patience.
</div>
<div slot="warn-content">
We’ll be doing some work on VA.gov. The maintenance will last X hours. During that time, you won’t be able to sign in or use tools.
</div>
</va-maintenance-banner>
`);
});
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The tests for non-rendering scenarios (when the banner is expired or before the warning start date) use attribute-based content rather than slotted content. This means there's no test coverage for verifying the slot removal behavior when preventRender is true. Consider adding a test that uses slotted content (like the rendering tests do) to verify that slot removal works correctly even when the component doesn't ultimately render.

Copilot uses AI. Check for mistakes.
Comment on lines +31 to +32
isWarning: boolean = false;
preventRender: boolean = false;
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The property preventRender is declared with an initial value of false but is never reset back to false after being set to true. This could cause issues if the component instance is reused or if props change dynamically. Consider using @State() decorator for this property since it affects rendering, or ensure it's properly managed through the component lifecycle when props change.

Copilot uses AI. Check for mistakes.
RyanMunsch and others added 2 commits February 13, 2026 11:29
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

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

Thanks for working on this @RyanMunsch. I was able to confirm that the component successfully leaves only the appropriate warning OR maintenance slot in the light DOM when one of them is active.

However, I found that when the date is outside both the maintenance and warning windows (for example, if the windows are in the past), the component leaves everything in the DOM.

Here are the values I used (which should match the current implementation on va.gov):

  • 'upcoming-warn-start-date-time': "Mon Jun 08 2020 19:00:00 GMT-0700 (Mountain Standard Time)"
  • 'maintenance-start-date-time': "Tue Jun 09 2020 07:00:00 GMT-0700 (Mountain Standard Time)"
  • 'maintenance-end-date-time': "Wed Jun 10 2020 07:00:00 GMT-0700 (Mountain Standard Time)"

Can you look into methods for preventing that content from being accessible when there is no active maintenance or warning alerts?

Let me know if I am misunderstanding anything here!

@RyanMunsch
Copy link
Copy Markdown
Contributor Author

Good catch, @amyleadem. I pushed an update that should resolve that issue. Good for another look when you have the chance.

@RyanMunsch RyanMunsch requested a review from amyleadem February 20, 2026 17:57
Copy link
Copy Markdown
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

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

This is looking good to me from an accessibility perspective! I reviewed the rendered code and found that the component now removes everything from the light DOM except for what currently applies to the component.

I had a couple of open questions related to refining the logic and code. Let me know if you have any questions.

@RyanMunsch RyanMunsch requested a review from amyleadem February 23, 2026 18:41
@RyanMunsch
Copy link
Copy Markdown
Contributor Author

Thanks for the suggestions, @amyleadem. This is ready for another round when you are.

Copy link
Copy Markdown
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

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

LGTM! I had one open question about some possible redundant logic, but I don't think it is hurting anything. Mostly just wanting to understand.

Since there are few rounds of changes here, I'd like to one more engineering review/re-review before merge. @jamigibbs @powellkerry

Comment on lines +141 to +144
warningStartInFuture ||
maintenanceEndInPast ||
bothWindowsInPast ||
bothWindowsInFuture ||
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.

question(non-blocking): Why are bothWindowsInPast and bothWindowsInFuture needed? Curious if I am missing a configuration gap that this is helping with, or if they are redundant. If they are doing some safety checks, can we add a comment explaining?

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.

Wow, this should have been obvious to me but just now realizing what you meant in your previous round of comments. bothWindowsInFuture is indeed not necessary due to warningStartInFuture alone being enough to prevent render. Thank you, @amyleadem!

@RyanMunsch RyanMunsch requested a review from jamigibbs February 23, 2026 20:33
Copy link
Copy Markdown
Contributor

@jamigibbs jamigibbs left a comment

Choose a reason for hiding this comment

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

Thanks, Ryan! 🚀

@RyanMunsch RyanMunsch merged commit 229dd94 into main Feb 24, 2026
7 checks passed
@RyanMunsch RyanMunsch deleted the 4649-maintenance-banner-announcement branch February 24, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch Patch change in semantic versioning

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hidden content in va-maintenance-banner is announced by Speechify

5 participants