Phoenix Modal closing when form field highlighted

I have a phoenix live view resource, which contains some text fields.

The resource was created by phx.gen.live and the form is essentially default out of the box, the echo schema looks like this:

defmodule UpTally.Services.Tsl do
  use Ecto.Schema
  import Ecto.Changeset

  schema "tsl" do
    field :interface, EctoFields.IP
    field :ip, EctoFields.IP
    field :name, :string
    field :port, :integer
    field :tsl_version, Ecto.Enum, values: [:tsl_v3, :tsl_v5]
    field :send_interval, :integer
    field :tsl_offset, :integer
    field :polling_interval, :integer
    field :polling_enabled, :boolean

    timestamps()
  end

  @doc false
  def changeset(tsl, attrs) do
    tsl
    |> cast(attrs, [
      :name,
      :ip,
      :port,
      :interface,
      :tsl_version,
      :send_interval,
      :tsl_offset,
      :polling_interval,
      :polling_enabled
    ])
    |> validate_required([
      :name,
      :ip,
      :port,
      :interface,
      :tsl_version,
      :send_interval,
      :tsl_offset,
      :polling_interval,
      :polling_enabled
    ])
    |> validate_if_ip(:interface)
  end

  defp validate_if_ip(changeset, field) when is_atom(field) do
    validate_change(changeset, field, fn field, value ->
      case UpTally.Interfaces.is_valid?(value) do
        true ->
          []

        false ->
          [{field, "Is not a valid local interface address."}]
      end
    end)
  end
end

If I click to edit one of the items, triggering the modal to be displayed, and then highlight some of the text in one of the form fields the modal closes. It happens every time, consistently.

Any idea what is causing this, or something I can change to stop it :slight_smile:

Here is the form:

defmodule UpTallyWeb.TslLive.FormComponent do
  use UpTallyWeb, :live_component

  alias UpTally.Services

  @impl true
  def render(assigns) do
    ~H"""
    <div>
      <.header>
        <%= @title %>
      </.header>
      <.simple_form
        for={@form}
        id="tsl-form"
        phx-target={@myself}
        phx-change="validate"
        phx-submit="save"
      >
        <.input field={@form[:name]} type="text" label="Name" />
        <.input field={@form[:ip]} type="text" label="TSL Transmit IP" />
        <.input field={@form[:port]} type="number" label="TSL Transmit Port" />
        <.input field={@form[:tsl_offset]} type="number" label="TSL ID Offset" />
        <.input field={@form[:interface]} type="text" label="Local Interface IP" />
        <.input
          field={@form[:tsl_version]}
          type="select"
          label="Tsl Protocol version"
          options={get_tsl_options()}
        />
        <:actions>
          <.button phx-disable-with="Saving...">Save Tsl</.button>
        </:actions>
        <.input
          field={@form[:send_interval]}
          type="number"
          label="TSL Send delay between each message"
        />
        <.input field={@form[:polling_enabled]} type="checkbox" label="Enable TSL polling send" />
        <.input field={@form[:polling_interval]} type="number" label="Polling interval" />
      </.simple_form>
    </div>
    """
  end

  @impl true
  def update(%{tsl: tsl, action: action} = assigns, socket) when action == :edit do
    changeset = Services.change_update_tsl(tsl)

    {:ok,
     socket
     |> assign(assigns)
     |> assign_form(changeset)}
  end

  @impl true
  def update(%{tsl: tsl} = assigns, socket) do
    changeset = Services.change_tsl(tsl)

    {:ok,
     socket
     |> assign(assigns)
     |> assign_form(changeset)}
  end

  @impl true
  def handle_event("validate", %{"tsl" => tsl_params}, socket) do
    changeset =
      socket.assigns.tsl
      |> Services.change_tsl(tsl_params)
      |> Map.put(:action, :validate)

    {:noreply, assign_form(socket, changeset)}
  end

  def handle_event("save", %{"tsl" => tsl_params}, socket) do
    save_tsl(socket, socket.assigns.action, tsl_params)
  end

  defp save_tsl(socket, :edit, tsl_params) do
    case Services.update_tsl(socket.assigns.tsl, tsl_params) do
      {:ok, tsl} ->
        notify_parent({:saved, tsl})

        {:noreply,
         socket
         |> put_flash(:info, "Tsl updated successfully")
         |> push_patch(to: socket.assigns.patch)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign_form(socket, changeset)}
    end
  end

  defp save_tsl(socket, :new, tsl_params) do
    case Services.create_tsl(tsl_params) do
      {:ok, tsl} ->
        notify_parent({:saved, tsl})

        {:noreply,
         socket
         |> put_flash(:info, "Tsl created successfully")
         |> push_patch(to: socket.assigns.patch)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign_form(socket, changeset)}
    end
  end

  defp assign_form(socket, %Ecto.Changeset{} = changeset) do
    assign(socket, :form, to_form(changeset))
  end

  defp notify_parent(msg), do: send(self(), {__MODULE__, msg})

  defp get_tsl_options() do
    [{"TSL v3.1", :tsl_v3}, {"TSL v5", :tsl_v5}]
  end
end

Here’s a link to a video of the behaviour:

https://drive.google.com/file/d/1bbL3PWfRf7oMfIz8G2pAXk5OwdcSuPfz/view?usp=sharing

Thanks!

Maybe You are going out of the modal when You select fields… and the modal close, because it is how it should react.

Try to select without going out the modal and check if it works…

UPDATE: I saw in your video You release the button outside the modal.

Ahhh, you know what, that’s exactly what’s happening (see video edited into the post_.

Any way to disable the modal closing if just a click-up rather than click-down happens outside the modal? Other than that I guess I just need to disable that functionality completely.

Thanks

Gareth

Unfortunately, I don’t think You can… and it is HTML related, it will happens like this on any site (nothing to do with Phoenix).

You might try to increase padding of the modal.