Generated with the help of an LLM.

Problem/Motivation

This problem exists in both 11.x and 12.x. This issue addresses the problem in 11.x only. See #3546787: Replace MessageCommand with an HTMX implementation for a long term resoution targeting main.

When an htmx request swaps in only part of its response, queued status messages are deleted from the session and never shown. This affects messages from earlier requests and from the htmx request itself.

I hit this in #3593502: Introduce a new Menu UI to resolve memory issues and improve user experience. The new menu tree I'm working on loads child rows and search results through htmx with hx-select (or select in htmx.ajax()). Both keep only part of the response.

An htmx request gets an HTML response, by default the whole page. With the _htmx_route route option, or Htmx::onlyMainContent() on the request, HtmxRenderer returns a smaller document around the main content. Both render the queued messages. Rendering them deletes them from the session: StatusMessages::renderMessages() calls Messenger::deleteAll().

With hx-select, or the select option of htmx.ajax(), htmx swaps in only the matching elements, so the messages markup is dropped. The MR adds a Nightwatch test that fails on main: a button with hx-select requests a route that adds a status message, and the message never reaches the page's messages area.

Steps to reproduce

  1. In a custom module, add a route with _htmx_route: TRUE. Its controller calls \Drupal::messenger()->addStatus() and returns markup in a wrapper element.
  2. On another page, add a button with hx-get set to that route and hx-select set to the wrapper. Click it.
  3. Load any page. The message isn't shown.

My MR has a test which demonstrates the bug.

Proposed resolution

Show the messages from an htmx response in the page's messages area, as Ajax responses do. An out-of-band swap of the messages isn't affected by hx-select.

Remaining tasks

  • Ajax system maintainer review of the approach.
  • Accessibility review: Drupal.Message.add() passes a message to Drupal.announce(), and messages swapped in from a response don't go through it.
  • Frontend review(?)

User interface changes

Status messages from htmx requests that use hx-select show in the page's messages area.

Introduced terminology

None.

API changes

Depends on the resolution.

Data model changes

None.

Release notes snippet

Issue fork drupal-3635987

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

darvanen created an issue. See original summary.

darvanen’s picture

Title: Status messages are deleted without being shown when an htmx request uses hx-select » Status messages are lost when an htmx request uses hx-select
darvanen’s picture

The fix makes drupal.htmx depend on drupal.announce, and that changed two Umami performance tests.

Announce and debounce used to share an aggregate with drupal.message, loaded after drupal.htmx. Now they load before drupal.htmx, so that aggregate splits in two. Pages that load htmx and drupal.message load one more script.

Announce was already on those pages, so the extra bytes are only the larger htmx-assets.js (about 2 KB). Listing announce first in the dependencies doesn't avoid the split. I also tried after: core/drupal.message on drupal.htmx. That put drupal.message between loadjs and drupal.htmx, adding another script instead.

I've updated the expectations for three pages: the authenticated and editor front pages, and the admin node page.

darvanen’s picture

Title: Status messages are lost when an htmx request uses hx-select » Status messages are lost when using hx-select
darvanen’s picture

Assigned: darvanen » Unassigned
Status: Active » Needs review

Pretty sure that one Nightwatch failure is a flake, if so it'll probably self-heal like I've been seeing MRs do lately.

I'm not 100% confident in the solution I'm presenting here but it seems like the best approach to me: by default messages accompanying an htmx response get placed in the standard spot at the top of the page, but I've added a method so that htmx consumers can designate a better spot for their own status messages.

fathershawn’s picture

This is a thoughtful approach with a least change solution on our main branch with htmx 4. As it happens I've been working with a more disruptive change in #3546787: Replace MessageCommand with an HTMX implementation which uses the new hx-partial tag in htmx 4. In that issue I am imagining deprecating MessageCommand as part of our general deprecation of the Ajax API, and Drupal.announce to further reduce our page and maintenance weight. I'm also trying to hear the concerns in #3396318: AJAX MessageCommand markup and styling differs from Theme default.

Over there I propose that we always render the status message containers, using modern CSS to set the inner parts not to display when they do not contain messages. As these are properly annotated for accessibility, when a message is dynamically inserted, they not only then do display to sighted users, the are announced as well.

This allows us to wrap single messages in hx-partial and return them along with whatever we are sending in the response and they swap themselves into targets that are reliable. The functional part of that MR has no additional javascript, and restores a template for individual messages so that themes can do what they like with message display as long as they have the expected data properties on the structural tags.

D11 is still broken though, so perhaps we could focus this issue there? The hx-partial tag has been backported to htmx 2 in the latest version and that update is coming to us in 11.5. D11 is with us until D13.

darvanen’s picture

Version: main » 11.5.x-dev
Assigned: Unassigned » darvanen
Status: Needs review » Needs work

Oh dropping the old MessageCommand would be great, I searched for duplicates but I'm not really across this subsystem, thanks for pointing it out.

Do you think the Nightwatch test from here would help in #3546787: Replace MessageCommand with an HTMX implementation?

Very happy to address 11.x here, I see the dev branch is cut already, I'll take a look.

fathershawn’s picture

Excellent! I’m excited to work together on these. I’ll copy the Nightwatch test after I work through all the other tests that I broke with my disruption.

darvanen’s picture

Assigned: darvanen » Unassigned
Status: Needs work » Needs review

#3546787: Replace MessageCommand with an HTMX implementation changes the messages that HtmxRenderer renders. The test here sends hx-select to an ordinary route, which gets a full page from the normal page renderer, so the select still drops the messages there, I checked.

For 11.x I've got the same fix I proposed before ready, ported to htmx 2. @fathershawn is that what you meant for this issue, or did you mean waiting for hx-partial in #3625623: Update JavaScript dependencies for 11.5.0 and backporting the work you're doing?

quietone’s picture

If this is only for 11.x can you comment in the issue summary? Also, is this a regression?

fathershawn’s picture

Issue summary: View changes

@quietone I updated the IS. The fix in this issue only works for 11.x.

I don't think it qualifies as a regression in that it fixes something that requires manual intervention without this fix. It is possible in 11.x to remediate that behavior by adding an appropriately structured hx-select-oob to each htmx powered element that performs an additional select and swap of the status messages. That's a bit laborious and not what devs are used to coming from the Ajax API.

fathershawn’s picture

For 11.x I've got the same fix I proposed before ready, ported to htmx 2. @fathershawn is that what you meant for this issue, or did you mean waiting for hx-partial in #3625623: Update JavaScript dependencies for 11.5.0 and backporting the work you're doing?

I don't want to backport what I'm doing for D12, it seems too disruptive in 11.x. I did want to alert you to the upstream backport of hx-partial in case that helped with your solution but this reads like it's well in hand. I have one question on the MR.

darvanen’s picture

Thanks for the clarification, I thought that was what you meant but I wanted to be sure.

Answered in the MR.