low mumble. all

Modifying content outside of target element with hx-swap-oob

Published on

I can't tell if I'm an idiot or the HTMX docs aren't very comprehensive, but I really struggled to figure out how to do this really simple thing.

And it is really simple.

The issue, at least for me, came from HTMX requests only rendering a partial view of the page (which is what HTMX does) and I wanted to modify an element outside of the element specified with hx-target. hx-swap-oob is great for solving this exact issue.

In my case, I wanted to add an element to my header when in a specific view and remove it from the header when in a different view. Simple enough, right?

Here's how it works with HTMX. I'm going to exclude as much unnecessary code as possible to keep it easy to understand (hopefully).

A header that exists outside of element that I've specified with hx-target

<header>
    <h1>Some Thing</h1>
    <!-- This is where I want to add a back button -->
</header>

A partial/component template that will render in my hx-target element, BUT I want to modify an element elsewhere

<!-- This div WILL NOT actually render in the header -->
<!-- Only the content will be rendered, i.e. the back button -->

<div hx-swap-oob="beforeend:header">
    <button id="home_btn" hx-get="/home/" hx-target="main">Go home</button>
</div>

<!-- The content rendered in the hx-target element -->
<section>
    <p>Some content about stuff</p>
</section>

So at this point, the "Go home" button will be rendered in the header when this snippet gets rendered. The header will look like this:

<header>
    <h1>Some Thing</h1>
    <button id="home_btn" hx-get="/home/" hx-target="main">Go home</button>
</header>

Just like you would hope.

The problem is that when you click the "Go home" button, you will go home (good), but the "Go home" button will still be there (bad).

You can delete elements with hx-swap-oob

In the snippet that will be rendered when you click "Go home", you just need to add another div (that won't actually be rendered in the DOM) with hx-swap-oob="delete" and specify the ID of the element you want to delete.

<!-- Again, this will not actually be rendered in the DOM -->
<div hx-oob-swap="delete" id="home_btn"></div>

<!-- The content rendered in <main></main> -->
<h2>I'm Home!</h2>
<p>Hooray!</p>

And that's it. Good job.