LiveView can't add the tailwindcss class names that has color variants

Hi! I’m building a simple liveview html previewer where:

  1. a user inputs html code in textarea
  2. user clicks preview then it shows the result as html
  3. user can also add tailwindcss class names

It is similar to what tailwind playground offers.

Question: When a user adds class names in the textarea like text-green-900 or any that has color variants, it can’t apply the green text. Why is that?

repo: GitHub - jaeyson/editor
Here’s what I did:

<div class="flex gap-8">
  <.form for={@form} phx-submit="save" class="border rounded w-full bg-gray-50 p-4">
    <.input field={@form[:html_input]} type="textarea" placeholder="insert html here!" />
    <div>
      <.button type="submit" name="save" value="preview" class="p-1 border rounded">
        Preview
      </.button>
      <.button
        phx-disable-with="Saving..."
        type="submit"
        name="save"
        value="save"
        class="p-1 border rounded"
      >
        Save
      </.button>
    </div>
  </.form>
  <div class="border rounded w-full bg-gray-50 p-4">
    <%= Phoenix.HTML.raw(@preview) %>
  </div>
</div>
defmodule EditorWeb.EditorLive.Index do
  use EditorWeb, :live_view

  @impl true
  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign(:preview, "")
      |> assign(:form, to_form(%{}, as: :editor))

    {:ok, socket}
  end

  @impl true
  def handle_event(
        "save",
        %{"editor" => %{"html_input" => html_input}, "save" => "preview"},
        socket
      ) do
    socket = assign(socket, :preview, html_input)

    {:noreply, socket}
  end
end

I would wager that the Tailwind JIT is omitting the CSS classes for any of the strings that do not already appear in your own Phoenix codebase. That means by the time the page renders in the browser, the extra classes don’t have any meaning attached to them.

2 Likes

What I found out was: adding e.g. text-green-500 in the page, it’s added in priv/static/assets/app.css (dev). That meant it’ll only add when it’s needed? If so, is it possible/viable if I:

  1. User inputs an html string (e.g. <span class="text-green-500">test</div>)
  2. Take the input add it as an assigns
  3. ?display it?
  4. ?tell tailwind I added another class name?

#3 and #4 is confusing for me as which should be first and if this is possible

Yes, Tailwind only creates class for classes found in your codebase. This is configured under the content key in your assets/tailwind.config.js.

You can use a safelist to add classes that don’t show up in your code. If you are only allowing colours, it would be a pretty big list and you’d end up with a fairly large CSS file, but it’s doable. If you are doing all of Tailwind, that would complete untenable and you’d end up with a massive file. You would have to run the tailwind cli against the user’s input to the CSS output and add it to the DOM. I’m not sure if there are any security risks or anything there, this is something I’ve never really thought about before.

In any event, you can learn more if you read the whole section the safelist stuff is in.

1 Like

That’s what tailwinds playground does. It generates the css specifically for each playground instance, which is then injected into the head of the preview shown in an iframe. It doesn’t use the css from the playground website itself to begin with.

1 Like

Ah nice, thanks! I assumed but I wasn’t sure so I didn’t want to go suggesting it.

Though if you do go this route, @soyjeansoy, make sure you read the docs for System.cmd vs System.shell as you don’t want to run into security issues passing user input to a shell command.

You can ship the compiler if you want users to be able to add whatever classes at runtime.

2 Likes

wow thanks for this! i’ll try it out!