How do I include an SVG within a button tag, using Phoenix.HTML.Form and the submit tag?

I have a form in my EEX file in my Phoenix project as follows:

<%= form_for @conn, Routes.user_path(@conn, :create), [as: :user], fn f -> %>

    <div>
      <%= label f, :email, class: 'sr-only' %>
      <%= email_input f, :email, required: true %>
    </div>

    <div>
      <%= label f, :password, class: 'sr-only' %>
      <%= password_input f, :password, required: true %>
    </div>

    <%= submit "Log in" %>

<% end %>

This generates a form with a button as follows:

<button type="submit">Log in</button>

But I would like more control over what is inside the <button></button> tag – I would like to add a bunch of other HTML inside the button tag, including some SVG images.

<button type="submit">
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"/>
    </svg>
</button>

How can I add my own SVG tags inside the button tag while still using the Phoenix.HTML.Form module as a helper to generate the button.

Or does it just not make sense for me to use the <%= submit "Log in" %> shortcut for my case? Since I’m doing everything within the form_for function, I’d like to be consistent with the way I generate other form elements, and also make sure I have my form all tied together properly.

1 Like

You can use do/end blocks instead of string labels for many html functions:

3 Likes

As a supplyment, it’s better to manage svg image with some helpers. Or, it will interfere with your view.

1 Like

When I try this code:

<%= submit "Log in" do %>
    <svg>
        ETC
    </svg>
<% end %>

I get the error undefined function submit/3

I guess that adding the do...end is like adding a third argument. So I guess submit/2 exists but submit/3 does not?

Skip the "Log in". It can be either text or a do/end block.

1 Like

Currently I pass information to the submit form helper so that I can style the button by setting the class.

<%= submit "Log in", class: "styling" %>

How can I set the class on the button if I jump directly into the do-end block?

Also, under what scenario do I gain a big advantage from using this submit helper from Phoenix.HTML.Form? It seems to me like it doesn’t really help much – it seems like different syntax for saying the same thing and I’m getting no magic lifting happening for me behind the scenes.

The button text (or other content) just gets placed inside the do-end block:

<%= submit class: "styling" do %>
  "Log In"
<% end %>

In this case "Log In" could be replaced with your <svg />.

Have a look at Phoenix.HTML.Tag.content_tag/2/3 to get a better understanding of how this works.

Thanks!!

In a Phoenix Liveview leex file, I reference an SVG in the button tag, then use CSS to style the button shape/color and the SVG attributes, such as position. Also, the button is disabled if the associated input field value is blank.

                  <button class="post_send_button" type="submit" name="submit" <%= if @post == "" do %>disabled="disabled"<% end %>>
                    <img class="send_img" src="<%= Routes.static_path(@socket, "/images/icons/send_white.svg") %>"/>
                  </button>

Following is CSS that renders a round button with the SVG centered, and to the right side of the associated input assigned a class value of post_send:

.post_send {
  display: flex;
  padding-bottom: 1.0rem;
}

.post_send_button {
  border-radius: 16px;
  height: 32px !important;
  width: 32px;
  margin-left: 0.3rem;
  margin-bottom: 0px;
  padding: 0px;
}

.send_img {
  height: 18px;
  width: 21px;
  margin: 0px;
  line-height: 0px !important;
  position: relative;
  left: -1px;
  top: 2px;
}