Why are AUI messages not deleted from the DOM?

After fade-out completes and display is set to none, the message HTML is still on the page, including its 4 event handlers.

Why? I can save my form over and over and keep filling up the DOM forever. Isn’t this considered bad practice to leave elements on the DOM that will never again be used? Is this a React thing?

Message component should remove the DOM node after closing it.
You can test this behaviour here https://docs.atlassian.com/aui/7.9.9/docs/messages.html

By React thing you mean that you are using this component inside a React app?

I think I mentioned react because of something I saw in the devtools/console. I am not using it.

I am using the following JS code on a custom admin page in Jira:

    AJS.$.ajax({
        ...
    }).done(function() {
        AJS.messages.success('#message-context', {
            title: 'title',
            body: '<p>message</p>',
            closeable: false,
            fadeout: true,
            delay: 2500
        });
    });

Here is a sample from codepen (https://codepen.io/DreamingVoid/pen/XWJxKWy) showing they do not disappear. I clicked it 3 times, and you can see they are still there:

Using Firefox 72.0.1 (64-bit) in Ubuntu 18.04.3 LTS.

Ok, I misunderstood your intention. Looking at code it looks like message needs to also be closable to be removed by fadeout.
This seems to be working as expected -> https://codepen.io/maciejszpyra/pen/PowyzyO
Please create issue here https://ecosystem.atlassian.net/browse/AUI because it looks like the docs should be amended.