The panel that closed itself

Projects
Elixir, Liveview

I made it so posts can live in multiple spaces: An “Also show in” panel of checkboxes lets it appear in others. A lot of checkboxes is a lot of form, so that added complexity.

<details class="post-form__also-interests">
  <summary><%= t("Also show in") %></summary>
  <div class="post-form__also-interests-options">
    <%= for interest <- @also_interest_options do %>
      ...

I found the bug while using the picker myself making the discussion thread for the previous post here. Open the panel, check a box, and the panel snaps shut. Open it again, check another box, shut again. Collapsed, it gives no sign anything is selected at all. This was a problem.

The bug #

The last panel bug on this blog was a race — three timers and a duplicate event, reproducible twice in many runs. This one is the opposite: perfectly deterministic, wrong every single time, and visible the moment you know where to look.

So reproducible it was (relatively) easy to write a smoke test for it.

A <details> element’s open attribute is written by the browser when the user clicks the summary. The server never hears about it. Meanwhile the composer is a LiveView form with live validation — every keystroke and every checkbox change makes a round trip, the server re-renders, and the patcher re-syncs the DOM to the server’s HTML. The server’s HTML has no open attribute, so the patcher removes it. Typing a single letter in the title field also closed the panel.

The fix #

Give the boolean to the server.

<button type="button" phx-click="toggle_also_interests"
        aria-expanded={to_string(@also_picker_open?)}>
  <%= t("Also show in") %>
  <%= if names != [] do %>
    <span><%= Enum.join(names, ", ") %></span>
  <% end %>
</button>
<div hidden={!@also_picker_open?}>
  ... the checkboxes ...
</div>

The checkbox list is hidden when collapsed, not conditionally rendered. Inputs that leave the DOM leave the form, and a reader who collapses the panel before submitting doesn’t silently lose their picks.

Bug fixed, time for a beer.

Replies come from Popsicle Boat members. Accounts are required, it’s why there’s no spam. You’ll sign in there (or create an account, it takes a short minute), confirm before it posts, and land right back here after.

512KB Club Orange Team member