Rails8 ViewComponent load css and stimulus JS files from components folder
Rails
ViewComponent
In Rails 8 with Propshaft & Importmaps
I use ViewComponent (3.21.0) and I would like to store Stimulus JS controllers and vanilla CSS files from within component folder
Someting like this :
app/ components/ tag_component.rb tag_component.html.erb tag_component_controller.js tag_component.css
Example content:
/* app/components/tag_component.css */ .tag { display: inline-block; padding: 0.5em 1em; background: #f44336; color: #fff; }
// app/components/tag_component_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { connect() { alert("Hello World!") } }
# app/components/tag_component.rb class TagComponent < ApplicationComponent def initialize(title:) @title = title end end
# app/components/tag_component.html.erb <div class="tag" data-controller="tag-component"> <%= @title %> </div>
# app/views/pages/index.html.erb <%= render(TagComponent.new(title: "Foo") %>
To achieve this I need to tell Propshaft and Importmaps to include `app/components` folder
# config/initializers/assets.rb # ... +Rails.application.config.assets.paths << "app/components" +Rails.application.config.importmap.cache_sweepers << Rails.root.join("app/components")
# config/importmap.rb # ... pin_all_from "app/components", under: "controllers", to: ""
Importmaps will recognize the JS file and Alert will pop (sofar code is production ready)
One more improvement we can do is to define
One more improvement we can do is to define
# app/components/application_component.rb class ApplicationComponent < ViewComponent::Base def stimulus_controller "#{self.class.name.underscore.dasherize.gsub('/', '--')}" end end
# app/components/tag_component.html.erb <div class="tag" data-controller="<%= stimulus_controller %>"> <%= @title %> </div>
Everything sofar is heavily inspired by article https://blog.theamazingrando.com/posts/rails-propshaft-stimulus-viewcomponent.html
When it comes to our CSS Propshaft needs explicitly load the component css from <style> tag. Sofar I got this ( following is not production ready)
# app/views/layouts/application.html.erb #... <head> <%# Includes all stylesheet files in app/assets/stylesheets %> <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %> <% Dir.glob("app/components/**/*.css").map{ File.basename(it, ".css") }.each do %> <%= stylesheet_link_tag it, "data-turbo-track": "reload" %> <% end %> <%= javascript_importmap_tags %> </head> #...