Components
Lato provides a set of reusable functional components.
By using Lato components, you can save development time and simplify maintenance tasks.
All components are available via the Lato::ComponentsHelper helper.
Source code: Lato::ComponentsHelper
Navbar
Navbar nav item
Component to render a menu item in the navbar.
Parameters:
- key: the menu item's key. Used to activate the item via the active_navbar function from the Lato::Layoutable concern.
- path: a path or absolute URL to redirect the user.
- &block: block of HTML to render inside the menu item.
<%= lato_navbar_nav_item :account, lato.account_path do %> Account <% end %>
Sidebar
Sidebar nav item
Component to render a menu item in the sidebar.
Parameters:
- key: the menu item's key. Used to activate the item via the active_sidebar function from the Lato::Layoutable concern.
- path: a path or absolute URL to redirect the user.
- &block: block of HTML to render inside the menu item.
There are also some extra parameters to customize the menu item:
- external (default: false): if true, an icon is added to indicate that the link opens in a new tab and a target="_blank" attribute is added to the link.
- children (default: nil): an array of hashes representing submenu items. Each hash should contain the keys :key, :label, and :path. If this parameter is provided, the menu item will have a collapsible submenu.
<%= lato_sidebar_nav_item :account, lato.account_path do %>
Account
<% end %>
<%= lato_sidebar_nav_item :github, 'https://github.com/Lato-org/lato', external: true do %>
GitHub
<% end %>
<%= lato_sidebar_nav_item :examples, '#', children: [
{ key: :products, label: 'CRUD Example', path: main_app.products_path },
{ key: :other, label: 'Other Examples soon..', path: '#' },
] do %>
Examples
<% end %>
Page
Page head
<%= lato_page_head 'Page title' %>
Page title
<%= lato_page_head 'Page title', [{ label: 'Title 1', path: main_app.page_path }, { label: 'Title 2' }] %>
Page title
<%= lato_page_head 'Page title' do %> <p class="lead">Welcome to this page</p> <% end %>
Page title
Welcome to this page
Form
Forms can be generated using the lato_form components.
lato_form components are a set of utilities designed to work with Rails' form_with helper and the Stimulus controller lato_form_controller.
Below is a list of available components with usage examples:
-
lato_form_noticesdisplays success feedback (notices set by the controller action). -
lato_form_errorsdisplays error feedback (based on model instance errors). -
lato_form_item_labelrenders the field label. -
lato_form_item_input_textrenders a text input. -
lato_form_item_input_numberrenders a number input. -
lato_form_item_input_emailrenders an email input. -
lato_form_item_input_passwordrenders a password input. -
lato_form_item_input_checkrenders a checkbox input. -
lato_form_item_input_selectrenders a select input. -
lato_form_item_input_filerenders a file input. -
lato_form_item_input_textarearenders a textarea input. -
lato_form_item_input_daterenders a date input. -
lato_form_item_input_datetimerenders a datetime input. -
lato_form_item_input_timerenders a time input. -
lato_form_item_input_colorrenders a color input. -
lato_form_submitrenders the submit button.
<%
user ||= @session.user
%>
<%= turbo_frame_tag 'tutorial_form-example' do %>
<%= form_with model: user, url: main_app.components_update_user_action_path, data: {
turbo_frame: '_self',
controller: 'lato-form'
} do |form| %>
<%= lato_form_notices class: %w[mb-3] %>
<%= lato_form_errors user, class: %w[mb-3] %>
<div class="row">
<div class="col col-12 col-lg-6 mb-3">
<%= lato_form_item_label form, :first_name, 'Name' %>
<%= lato_form_item_input_text form, :first_name, required: true %>
</div>
<div class="col col-12 col-lg-6 mb-3">
<%= lato_form_item_label form, :last_name, 'Surname' %>
<%= lato_form_item_input_text form, :last_name, required: true %>
</div>
</div>
<div class="row">
<div class="col col-12 col-lg-6 mb-3">
<%= lato_form_item_label form, :select, 'Select' %>
<%= lato_form_item_input_select form, :select, [['Type 1', '1'], ['Type 2', '2']], required: true %>
</div>
<div class="col col-12 col-lg-6 mb-3">
<%= lato_form_item_label form, :file, 'File' %>
<%= lato_form_item_input_file form, :file, required: true %>
</div>
</div>
<div class="row">
<div class="col col-12 mb-3">
<%= lato_form_item_label form, :textarea, 'Textarea' %>
<%= lato_form_item_input_textarea form, :textarea, required: true %>
</div>
</div>
<div class="row">
<div class="col col-12 col-lg-4 mb-3">
<%= lato_form_item_label form, :date, 'Date' %>
<%= lato_form_item_input_date form, :date, required: true %>
</div>
<div class="col col-12 col-lg-4 mb-3">
<%= lato_form_item_label form, :datetime, 'Datetime' %>
<%= lato_form_item_input_datetime form, :datetime, required: true %>
</div>
<div class="col col-12 col-lg-4 mb-3">
<%= lato_form_item_label form, :time, 'Time' %>
<%= lato_form_item_input_time form, :time, required: true %>
</div>
</div>
<div class="row">
<div class="col col-12 mb-3">
<%= lato_form_item_label form, :color, 'Color' %>
<%= lato_form_item_input_color form, :color, required: true %>
</div>
</div>
<div class="row">
<div class="col col-12 mb-3">
<%= lato_form_item_label form, :first_name, 'Name with auto-complete' %>
<%= lato_form_item_input_text form, :first_name, required: true, data: {
controller: 'lato-input-autocomplete',
lato_input_autocomplete_path_value: products_autocomplete_path
} %>
</div>
</div>
<div class="row">
<div class="col col-12 mb-3">
<%= lato_form_item_label form, :first_name, 'Name with auto-complete V2' %>
<%= lato_form_item_input_text form, :first_name, required: true, data: {
controller: 'lato-input-autocomplete2',
lato_input_autocomplete2_path_value: products_autocomplete_path
} %>
</div>
</div>
<div class="d-flex justify-content-end">
<%= lato_form_submit form, 'Update', class: %w[btn-success] %>
</div>
<% end %>
<% end %>
Index
The lato_index component allows easy visualization of database records.
Index (front-end)
The simplest way to use the component is to pass it an ActiveRecord collection:
<%= lato_index Product.all.limit(5) %>
Customizing columns
Columns can be customized using the :columns parameter:
<%= lato_index Product.all.limit(5), columns: %i[id code status] %>
Notes
Column titles can be customized using Rails translation files.
Example:
en:
activerecord:
attributes:
product:
code: Code
status: Status
Customizing column content
You can customize column content by creating helper methods with the format model_column(record).
For example, to customize the output of the :lato_user_id column, define the following helper in ProductsHelper:
class ProductsHelper
def product_lato_user_id(product)
product.lato_user.full_name
end
end
Adding custom columns
To add custom columns, declare a method in the model that provides the value.
For example, after adding a lifetime method to the Product model, you can use the :lifetime column:
class Product < ApplicationRecord
def lifetime
Time.now - created_at
end
end
class ProductsHelper
def product_lifetime(product)
Time.at(product.lifetime).utc.strftime('%H h %M m')
end
end
<%= lato_index Product.all.limit(5), columns: %i[id code status lifetime] %>
Notes
Custom columns can also be translated using Rails translation files, just like database-backed columns.
To add columns that don't map to real attributes, use attr_accessor :column_name instead of defining a method in the model:
class Product < ApplicationRecord attr_accessor :lifetime end
Adding actions
<%= lato_index Product.all.limit(5), custom_actions: {
create: {
path: products_create_path,
icon: 'bi bi-plus',
aria_label: 'Create product',
title: 'Create product'
}
} %>
Adding in-page actions
<%= lato_index Product.all.limit(5), custom_actions: {
create: {
path: products_create_path,
icon: 'bi bi-plus',
data: { lato_action_target: 'trigger', turbo_frame: dom_id(Product.new, 'form') },
aria_label: 'Create product',
title: 'Create product'
}
} %>
Notes
The :create_turbo_frame option specifies the turbo-frame ID in the products_create_path page that should be inserted into the overlay.
Adding row-specific actions
Row-specific actions can be added through custom columns (as shown above).
These actions can also be opened in-page via overlays using data-lato-index-target="action" and data-turbo-frame="turbo-frame-ID".
class ProductsHelper
def product_actions(product)
content_tag(:div, class: 'btn-group btn-group-sm') do
concat link_to(
'Edit',
products_update_path(product),
class: 'btn btn-primary',
data: { lato_action_target: 'trigger', turbo_frame: dom_id(product, 'form') }
)
end
end
end
<%= lato_index Product.all.limit(5), columns: %i[id code status lifetime actions] %>
Index (back-end)
To make the index fully interactive, use the lato_index_collection function from the Lato::Componentable concern in the controller.
def index @products = lato_index_collection(Product.all, pagination: true) end
<%= lato_index @products %>
Customizing columns
def index
@products_columns = lato_index_collection(
Product.all,
pagination: true,
columns: %i[code status id]
)
end
<%= lato_index @products_columns %>
Customizing pagination size
Users can choose how many items to display per page using a selector enabled via the :pagination_options parameter in lato_index_collection.
def index
@products_pagination_options = lato_index_collection(
Product.all,
pagination: 10,
columns: %i[code status id],
key: 'products_pagination_options'
)
end
<%= lato_index @products_pagination_options, pagination_options: [10,20,50,100] %>
Making columns sortable
def index
@products_sortable_columns = lato_index_collection(
Product.all,
pagination: true,
columns: %i[code status lato_user_id],
sortable_columns: %i[code status lato_user_id]
)
end
<%= lato_index @products_sortable_columns %>
Notes
To customize sorting logic, define the lato_index_order scope inside the model.
Example:
class Product < ApplicationRecord
belongs_to :lato_user, class_name: 'Lato::User'
scope :lato_index_order, ->(column, order) do
return joins(:lato_user).order("lato_users.last_name #{order}, lato_users.first_name #{order}") if column == :lato_user_id
order("#{column} #{order}")
end
end
Notes
To set a default sorting column, use the default_sort_by option in the lato_index_collection method.
Example:
def index
@products_default_sort = lato_index_collection(
Product.all,
pagination: true,
columns: %i[code status lato_user_id],
sortable_columns: %i[code status lato_user_id],
default_sort_by: 'code|asc' # 'column|direction'
)
end
Making columns searchable
def index
@products_searchable_columns = lato_index_collection(
Product.all,
pagination: true,
columns: %i[code status lato_user_id],
sortable_columns: %i[code status lato_user_id],
searchable_columns: %i[code lato_user_id]
)
end
<%= lato_index @products_searchable_columns %>
Notes
To customize search logic, define the lato_index_search scope inside the model.
Example:
class Product < ApplicationRecord
belongs_to :lato_user, class_name: 'Lato::User'
scope :lato_index_search, ->(search) do
joins(:lato_user).where("
lower(code) LIKE :search OR
lower(lato_users.first_name) LIKE :search OR
lower(lato_users.last_name) LIKE :search
", search: "%#{search.downcase.strip}%")
end
end
Skip total count for large tables
For large tables, you can skip the total count to improve performance by setting the :skip_total_count option to true in the lato_index method.
This is useful when you don't need the total count of records, such as when displaying a large collection.
<%= lato_index @products_skip_total_count_columns, skip_total_count: true %>