Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some integration support for Tailwindcss? #1723

Closed
DiegoOrejuela opened this issue Jan 15, 2021 · 11 comments
Closed

Some integration support for Tailwindcss? #1723

DiegoOrejuela opened this issue Jan 15, 2021 · 11 comments

Comments

@DiegoOrejuela
Copy link

Hi guys

I would like to ask if you are considering adding support to Tailwindcss

Thanks

@carlosantoniodasilva
Copy link
Member

I don't have experience with Tailwind to build anything out of the box, it's not something that's on my radar for the near term at least, but perhaps in the future.

I do think that the wrapper support in SF should be mostly enough to build a set of default configs for your own needs, and I'd be happy to support adding anything that might be missing, but I'm not sure about maintaining such configs with SF itself for now. If you (or someone else coming here) have a set of configs, maybe a starting point would be the wiki.

FWIW, Bootstrap support was added really long ago and is now mainly maintained via https://github.com/rafaelfranca/simple_form-bootstrap, and there hasn't been any changes for the past couple of years.

@abevoelker
Copy link

As mentioned in #1727, I made an attempt at adding a Tailwind component using the Wrappers API:

config.wrappers :tailwind_text_input, tag: 'div', class: '', error_class: '', valid_class: '' do |b|
  b.use :html5
  b.use :placeholder
  b.optional :maxlength
  b.optional :minlength
  b.optional :pattern
  b.optional :min_max
  b.optional :readonly

  b.use :label, class: "block text-sm font-medium text-gray-700"
  b.wrapper tag: 'div', class: 'mt-1', error_class: 'relative rounded-md shadow-sm' do |c|
    c.use :input,
      class: 'appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm',
      error_class: 'block w-full pr-10 border-red-300 text-red-900 placeholder-red-300 focus:outline-none focus:ring-red-500 focus:border-red-500 sm:text-sm rounded-md'
    c.use :full_error, wrap_with: { tag: 'p', class: 'mt-2 text-sm text-red-600' }
  end
end

Which I use like this:

<%= f.input :email, wrapper: :tailwind_text_input, autocomplete: "email", placeholder: "asmith@example.com", label: "Email address" %>

That wrapper is a first attempt to mimic this HTML:

<%= simple_form_for(@user, url: profiles_path, html: { class: "space-y-6" }) do |f| %>
  <div>
    <%= f.label :email, class: "block text-sm font-medium text-gray-700" do %>
      Email address
    <% end %>
    <%- if f.object.errors[:email].any? -%>
    <%- input_classes = "block w-full pr-10 border-red-300 text-red-900 placeholder-red-300 focus:outline-none focus:ring-red-500 focus:border-red-500 sm:text-sm rounded-md" -%>
    <%- else -%>
    <%- input_classes = "appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" -%>
    <%- end -%>
    <div class="mt-1  <%= 'relative rounded-md shadow-sm' if f.object.errors[:email].any? %>">
      <%= f.text_field :email, autocomplete: "email", required: true, placeholder: "asmith@example.com", class: input_classes %>
      <%- if f.object.errors[:email].any? -%>
      <div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
        <!-- Heroicon name: solid/exclamation-circle -->
        <svg class="h-5 w-5 text-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
          <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
        </svg>
      </div>
      <% end %>
    </div>
    <%- if f.object.errors[:email].any? -%>
    <p class="mt-2 text-sm text-red-600"><%= f.object.errors.full_messages_for(:email).join(", ") %></p>
    <%- end -%>
  </div>

  <!-- (other fields elided) -->
<% end %>

That HTML should render something like this given a fresh form with a blank model:

wN9Cj

And when there's an error, it will look something like this:

YO6Om

Besides the problem I mentioned in #1727 with the missing 'relative rounded-md shadow-sm' error classes, I had some other difficulties in modeling this component in Simple Form:

  1. I don't see a way to conditionally append the <svg> icon after the <input> when there's an error using the wrappers API. Presumably I'll have to write a custom input to support this?

  2. When it comes to classes, Simple Form seems to have the notion of class, error_class, and valid_class. It seems that the class is always used for the component, and error_class and valid_class are added on as additional classes if the component has errors or is valid, respectively. This doesn't work for my component, because I want my field's colors to be border-gray-300 focus:ring-indigo-500 focus:border-indigo-500 when the model is a new record, but if there's an error it should overwrite those classes with border-red-300 focus:ring-red-500 focus:border-red-500.

    The way it's working right now when there's an error, it adds my error classes on top of the indiglo classes, leading to me seeing indiglo outlines instead of red in Chrome:

    issue

    I can't figure out how to work around this besides either patching Simple Form's default behavior or doing something hacky like this:

    <%- if @user.new_record? -%>
    <%= f.input :email, wrapper: :tailwind_text_input, autocomplete: "email", placeholder: "asmith@example.com", label: "Email address", input_html: { class: 'appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm' } %>
    <%- else -%>
    <%= f.input :email, wrapper: :tailwind_text_input, autocomplete: "email", placeholder: "asmith@example.com", label: "Email address", input_html: { class: '' } %>
    <%- end -%>
    

    Is there a better way to handle that which I'm not seeing?

@abevoelker
Copy link

Well, I ended up creating a custom input and custom form builder to get the required behavior. Here's the gem in an early stage if anyone wants to help me add more Tailwind components.

@carlosantoniodasilva
Copy link
Member

@abevoelker thanks for all the information on tailwind here. Unfortunately like I mentioned above, I don't have much experience with tailwind, I hope to be able to learn that better at some point, but I'm happy to help and see if we can make SimpleForm flexible enough to support it.

I left a comment on #1727 about that not being something we currently support I believe. Regarding your questions:

  1. I don't see a way to conditionally append the icon after the when there's an error using the wrappers API. Presumably I'll have to write a custom input to support this?

I believe a custom input would be the way to go here, especially considering this is conditional to the error state.

When it comes to classes, Simple Form seems to have the notion of class, error_class, and valid_class. It seems that the class is always used for the component, and error_class and valid_class are added on as additional classes if the component has errors or is valid, respectively

Correct, the class is always there, the others only build on top, it's meant to be an always present/default class. There's no way to override class once you add it. It sounds like what you'd like is a fallback if no error is present for example, that'd likely be something different/custom to build.


It sounds to me that SF might need even more flexibility to achieve tailwind's requirements. I'll take a look at the gem code, see what I can learn from that as well, thanks for sharing that.

@abevoelker
Copy link

Unfortunately like I mentioned above, I don't have much experience with tailwind, I hope to be able to learn that better at some point, but I'm happy to help and see if we can make SimpleForm flexible enough to support it.

That's understandable, I'm still learning it myself even. Thanks for lending your support to the Simple Form side of things

I believe a custom input would be the way to go here, especially considering this is conditional to the error state.

Yeah you were correct - I ended up getting what I needed working with a custom input

Correct, the class is always there, the others only build on top, it's meant to be an always present/default class. There's no way to override class once you add it. It sounds like what you'd like is a fallback if no error is present for example, that'd likely be something different/custom to build.

Thanks for that - I ended up with a mixin that patches an input's behavior to do what I need which I'll use in my custom inputs.

It sounds to me that SF might need even more flexibility to achieve tailwind's requirements. I'll take a look at the gem code, see what I can learn from that as well, thanks for sharing that.

That would be great! Just one request - I'm just starting to get the hang of writing custom inputs and custom form builders; if you wouldn't mind waiting about one week to give me time to write more components and refactor the code, I think your time would be better spent. 😄

@carlosantoniodasilva
Copy link
Member

Sounds good, appreciate it @abevoelker. Feel free to ping back here once you think it's in a good place for further look :). Thanks again.

@yordis
Copy link

yordis commented May 23, 2021

@abevoelker would you mind sharing your configuration file? I would like to use it as the baseline 🙏🏻

@abevoelker
Copy link

abevoelker commented May 23, 2021 via email

@elliotlarson
Copy link

Given the popularity growth of Tailwind in the Rails community recently, it might be worth re-opening this?

@borama
Copy link

borama commented Jun 20, 2022

FWIW, here is our take on styling Simple Form forms with Tailwind while keeping them flexible. The solution uses a custom form builder and a set of helper methods to allow overriding default Tailwind classes flexibly.
https://dev.to/nejremeslnici/styling-simple-form-forms-with-tailwind-4pel

@Jules-Pinsard
Copy link

Hi,
I faced the same problem as you did, and I found the usage of important (!) classes to fix it.
So I made a template for a new rails app that provide you a form builder.
I used Flowbite as a template from the form.
Feel free to use it and to report any issue 😃
Cheerz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

7 participants