DEV Community

Steve Alex
Steve Alex

Posted on

Mimic Tailwind components in Rails using Helpers

I've been toying with Rails 7 alpha for the last month or so and this is a little expansion on My Bumpy Ride post. It is confirmed that in Rail 7, rails new xxx will default to importmaps. You can still use webpacker, but it will stop being upgraded. You also have the option of using esbuild which is like mini-webpacker - you get the bundling without all the webpacker bable stuff.

Recently I've added a little tailwindcss to a few of my apps. I have three semi-private apps that are used by a very small group of friends. None of the apps have a large amount of Javascript and all javascript has been converted to stimulus.js. But all the apps have messy mixture of css that have been through custom sass, Zurb Foundation and W3.css

The esbuild approach will probably be the best approach to upgrading a rails 6 app, but it won't be easy. Hopefully the Rails team will come up with some tools. I actually had the best results (just testing approach) by

  • Creating a new rails 7 app using esbuild
  • Adding my node stuff, including tailwind
  • Copying my controllers, models and views to the new app.

Lots of work. Could probably go the other way and copy the new rails app guts to the and existing app clone. Then deleting the webpacker stuff. Think I'll just wait for the upgrade!

The importmaps approach is the simplest. I had a few problems importing stimulus-flatpickr and getting it to work. Most of the problems came from stimulus being changed to @hotware/stimulus and getting versions to match.

That still left me with tailwind css that couldn't be modified (add my preferred colors, etc). It finally hit me that I can still write my own css in a utility first style and get my colors. That is provided I didn't create the crap classes that I used in the past that would eventually clash with other crap classes!

The few apps that I've added tailwind css to are actually using a mixture of W3.css and tailwind. I'm slowly converting the W3.css to tailwind when warranted. You still end up with he major complaint of tailwind - the hiedius markup.

/ markup using slim
section.bg-gray-900
  .max-w-5xl.mx-auto.px-4.py-24(class="sm:px-6 lg:px-8")
    h1.text-4xl.font-bold.tracking-wide.uppercase.text-center.text-white(class="sm:text-6xl")
      |Hello World
Enter fullscreen mode Exit fullscreen mode

Fortunately I don't have a marketing site with all the flashing components. I have simple buttons and some card-like sections.

It finally hit me that I could use rails Helpers to make life easier and keep me from creating a bunch of css classes that are almost all the same.

Lets create a couple simple buttons and boxes.

module ComponentsHelper
  def greenBox
    "box-border box-content m-3 p-4 bg-green-300 border-green-100 border-2 text-black"
  end

  def blueBox
    "box-border box-content m-3 p-4 bg-blue-400 border-blue-200 border-2 text-black"
  end

  def btn
    "py-1 px-2 text-black hover:text-white rounded font-lg font-bold "
  end

  def btnInfo
    btn + "bg-blue-400 hover:text-blue-200"
  end

  def btnWarn
    btn + "bg-orange hover:text-yellow-300"
  end

  def btnDanger
    btn + "bg-red-500 hover:text-red-200"
  end

  def btnSuccess
    btn + "bg-success"
  end

  def btnSecondary
    btn + "bg-secondary"
  end

  def flashAlert(type)
    case type
    when 'danger'
      return "bg-red-200 text-red-600"
    when 'info'
      return "bg-blue-200 text-blue-600"
    when 'success'
      return "bg-green-200 text-green-600"
    when 'warning'
      return "bg-yellow-400 text-yellow-800"
    else
      return "bg-gray-200 text-gray-600"
    end
  end

end
Enter fullscreen mode Exit fullscreen mode

Just a simple rails helper using tailwind classes and a few custom colors (bg-orange, bg-success). Now my buttons are all about same and it would be easy to add others.

The markup changes to something like:

 div.mx-10.flex-grow.px-2
      button[class="#{btnInfo} mr-2" data-action="click->entryLedger#check_valid"] Validate
      button[class="#{btnWarn} mr-2"] = link_to('Cancel', session[:current_acct].present? ? account_path(session[:current_acct]) :request.headers['HTTP_REFERER'],
        class:"")
      - unless @entry.new_record? || @entry.reconciled?
        - confirm_msg = @entry.cleared? ? "Entry has been Cleared - Are you sure?" : 'Are you sure?'
        button[class="#{btnDanger} mr-2"] = link_to 'Delete Entry',@entry, data: { confirm: confirm_msg }, method: :delete 
Enter fullscreen mode Exit fullscreen mode

Again I use slim-rail, but an erb would just replace the #{} with erb tags.

This approach may make the importmaps more acceptable.

Top comments (3)

Collapse
 
phawk profile image
Pete Hawkins

Have you tried using view_component? It’s created by GitHub and allows a more complete approach to components than view partials/helpers. Highly recommend checking it out, it works great with tailwind!

Collapse
 
salex profile image
Steve Alex

That's actually on my list of to do's. I've read a little about it, just have not tried it yet.

Collapse
 
collimarco profile image
Marco Colli

This is completely against the philosophy of Tailwind: style and markup should stay together.

At this point, just use normal classes and CSS.