Ask A Question


You’re not receiving notifications from this thread.

Create (or not) a BaseComponent to work with TailwindCSS and ViewComponent?

Andrea Barghigiani asked in Rails

Hi all,
this is my first post and I am working with Ruby and Ruby on Rails for about a month. I have years of experience as a web developer but my focus was more on the Frontend part, if you don't count the WordPress experience.
I am trying to build some side projects to get me comfortable with Ruby and I am trying to use the ViewComponent and TailwindCSS just for practice.

As commonly happen I got confused setting up my project.

The scope of the app I am building is not important for now because I got stuck at creating a sort of design system that uses Tailwind CSS classes under the hood. Right now my focus is to create a sort of general ViewComponent that will let me define those classes passing attributes. Basically, I am creating a general BaseComponent that is supposed to handle all the class setting stuff:

<%= render
  bgc: "blue-300",
  color: "gray-100",
  m: 3
) %>

This is how I think to invoke the BaseComponent and the idea behind this is that all my components should inherit this class to compose the classes in an easier way, but before to give you an example here's the class:

class BaseComponent < ViewComponent::Base
  def initialize(styles)
    @styles = styles
    @c = []

  def classes
    # Calling internal methods before return

  def colors
    @c << "bg-#{@styles[:bgc]}" if @styles[:bgc]
    @c << "text-#{@styles[:color]}" if @styles[:color]

  def margins
    # Global
    @c << "m-#{@styles[:m]}" if @styles[:m]
    # Positive
    @c << "my-#{@styles[:my]}" if @styles[:my]
    @c << "mt-#{@styles[:mt]}" if @styles[:mt]
    @c << "mb-#{@styles[:mb]}" if @styles[:mb]
    @c << "mx-#{@styles[:mx]}" if @styles[:mx]
    @c << "mr-#{@styles[:mr]}" if @styles[:mr]
    @c << "ml-#{@styles[:ml]}" if @styles[:ml]
    # Negative 
    @c << "-m-#{@styles[:n_m]}" if @styles[:n_m]
    @c << "-my-#{@styles[:n_my]}" if @styles[:n_my]
    @c << "-mt-#{@styles[:n_mt]}" if @styles[:n_mt]
    @c << "-mb-#{@styles[:n_mb]}" if @styles[:n_mb]
    @c << "-mx-#{@styles[:n_mx]}" if @styles[:n_mx]
    @c << "-mr-#{@styles[:n_mr]}" if @styles[:n_mr]
    @c << "-ml-#{@styles[:n_ml]}" if @styles[:n_ml]

From my point of view, this is already getting too complex and this is the reason I am writing to you, I just handled a bunch of color and margins and the code seems just too much from what I saw from the Rails codebase I working on and on many tutorials. Also Rubocop tells me that the margin method is already too complex since it has too many lines of code 😊

The idea behind this "mess" is for example that in a ButtonComponent I could setup it like the following:

<%= render
  style: "rounded",
  variant: "primary"
) %>

And within the class that defines it check the values of the attributes and build the class from the dedicated parent methods.

I would like to confront with you because all the tutorials that I saw that mixes ViewComponents and TailwindCSS the classes is embedded in the ERB template and from my point of view this is a good use for that single button, but it will not help me if I need to give more flexibility to my components.

So here's my question: what do you think of this approach? Shall I just forget about the BaseComponent and build the TailwindCSS classes right inside the single component? Something like:

class ButtonComponent < ViewComponent::Base
    def initialize(
        style: "square",
        variant: nil
        @style = style
        @variant = variant

    def classes
        c = ["standard-tailwind-classes"]
        c << "rounded-full" if @style == "pil"
        c << "rounded-md" if @style == "rounded"
        c << "bg-green-600 text-gray-100" if @variant == "primary"
        c << "bg-red-700 text-gray-100" if @variant == "danger"
        c.join(' ')

Or shall I just keep trying to get the flexibility that TailwindCSS offers passing attributes to my ViewComponents?

As you can see I am a bit confused πŸ˜‚


Well after a first look at the Primer BaseComponent I should start create some helper methods to handle this situation.

I am still new with the OOP paradigm and Rails in general. Even if this could be a great opportunity to learn it I am starting to think that probably will be better for me if I stick with the focus of the project to get experienced with Rails while following closely the evolution in the ViewComponent repo.

I know you don't know my experience but I'll asking anyway: do you think will be a better use of my time? 😊


If I have the rule increment value functions, can I include them in a jump function

Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 81,149+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

    © 2024 GoRails, LLC. All rights reserved.