Ruby on Rails view Components framework
Lite::Component is a library for building component base objects. This technique simplifies and organizes often used or logically complex page objects.
Add this line to your application’s Gemfile:
gem 'lite-component'
And then execute:
$ bundle
Or install it yourself as:
$ gem install lite-component
Use rails g component NAME will generate the following files:
app/assets/javascripts/components/[name].js
app/assets/stylesheets/components/[name].scss
app/components/[name]_component.rb
app/views/components/_[name].html.erb
The generator also takes --skip-css, --skip-js and --skip-erb options. It will also
properly namespace nested components.
If a ApplicationComponent file in the app/components directory is available, the
generator will create file that inherit from ApplicationComponent if not it will
fallback to Lite::Component::Base.
Component’s *.scss and *.js will be automatically load via the tree lookup in basic
Rails setups.
If you want to access route helpers in *_component.rb just include them like:
# app/components/alert_component.rb
class AlertComponent < Lite::Component::Base
include Rails.application.routes.url_helpers
def link_to_account
link_to('Return to account', account_path, class: 'text-underline')
end
end
To render a component in any view template or partial, you can use the the provided helper.
Its has the same setup as render and takes all Action View Partials
options.
<%= component("alert") %>
<%= component(AlertComponent, locals: { message: "Something went right!", type: "success" }) %>
Render namespaced components by following standard naming conventions:
<%= component("admin/alert") %>
<%= component(Admin::AlertComponent) %>
Render collection of components just as you would render collections of partials.
<%= component("comment_card", collection: @comments, spacer_template: "components/spacer") %>
If you can skip rendering by evaluating complex logic in the render? method:
# app/components/alert_component.rb
class AlertComponent < Lite::Component::Base
def render?
object.some_complex_check?
end
end
All components include ActionView::Context which will give you access to request context such as
helpers, controllers, etc. It can be accessed using context or c methods.
# app/components/alert_component.rb
class AlertComponent < Lite::Component::Base
def protected_page?
context.controller_name == 'admin'
end
end
All components include ActionView::Helpers which will give you access to default Rails
helpers without the need to invoke the context. Use the helper methods to access helper methods
from your app/helpers directory. It can be accessed using helpers or h methods.
# app/components/alert_component.rb
class AlertComponent < Lite::Component::Base
def close_icon
h.icon_tag(:close)
end
def link_to_close
link_to(close_icon, '#', data: { alert: :dismiss })
end
end
All components include access to partial locals via the locals or l methods.
You can dump locals to hash via the to_h and to_hash methods.
Note: Objects will be automatically added to locals when rendering collections.
<%= component("alert", locals: { object: @user }) %>
# app/components/alert_component.rb
class AlertComponent < Lite::Component::Base
def type_tag
<<~HTML.squish.html_safe
<b>#{locals.object.first_name}!</b>
HTML
end
end
All components will hav access to an iteration object which can be accessed
using the iteration or i methods. It provides access to each iterations
first?, last?, size, and index methods.
<%= component("alert", collection: @users) %>
# app/components/alert_component.rb
class AlertComponent < Lite::Component::Base
def limit_hit?
i.index == 5
end
end
For the following examples, components will have the following setup:
# app/components/alert_component.rb
class AlertComponent < Lite::Component::Base
def link_to_back
link_to('Go back', :back, class: 'text-underline')
end
end
<%= component("alert", collection: @users, locals: { message: "Something went right!", type: "success" }) %>
Component view partials behave just as a normal view partial would. All locals can be accessed by their key.
<%# app/views/components/_alert.html.erb %>
<div class="alert alert-<%= type %>" role="alert">
<%= message %>
</div>
Access to anything provided within its *_component.rb file can be done using the
component or c local methods which is the instance of the component.
<%# app/views/components/_alert.html.erb %>
<div class="alert alert-<%= type %>" role="alert">
<%= component.locals.message %>
<%= component.link_to_back %>
</div>
Rendering a collection will automatically give you access to the iteration and object variables.
<%# app/views/components/_alert.html.erb %>
<div class="alert alert-<%= type %>" role="alert">
<% if iteration.size > 1 %>
Alert #<%= iteration.index %>
<% content_tag(:br, nil) unless iteration.last? %>
<% end %>
Hi <%= object.first_name %>,
<br />
<%= message %>
</div>
To bypass having a partial and just rendering content directly override the render_content method.
# app/components/alert_component.rb
class AlertComponent < Lite::Component::Base
def render_content
content_tag(:span, 'Success', class: "alert-#{l.type}")
end
end
To add components as part of another component build a block and yield it in the component’s view.
<%# app/views/components/_sidebar.html.erb %>
<div class="sidebar">
<%= component("sidebar/navigation", locals: { class_name: "js-nav-links" }) do |c| %>
<% c.add("sidebar/navigation/link", locals: { text: "Link: 1", path: "/home", active: false }) %>
<% c.add("sidebar/navigation/link", locals: { text: "Link: 2", path: "/about", active: true }) %>
<% c.add("sidebar/navigation/link", locals: { text: "Link: 3", path: "/help", active: false }) do |n_c| %>
<% n_c.add("sidebar/something", locals: { test: "something" }) %>
<% end %>
<% end %>
</div>
<%# app/views/components/sidebar/_navigation.html.erb %>
<div class="sidebar-navigation">
<%= c.yield %>
</div>
<%# app/views/components/sidebar/navigation/_link.html.erb %>
<%= link_to(text, path, class: ("active" if l.active)) %>
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/lite-component. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the Lite::Component project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.