The forms component from Instrumental Components powers up your Rails app's forms by providing consisten form styling and handling various types of form fields.
At it's core is the form-control
CSS class, which gives all form fields a consistent look and feel.
The forms component also provides additional styling and funtionality for handling various other form-related things in Rails such as:
rails g instrumental:forms
To insert a sample form into a view:
rails g instrumental:forms:insert
To style a form field using Instrumental Components, simply wrap your Rails form field helper in the _field
partial, like this:
<%= render "shared/components/forms/field",
form: f,
label: "Name",
name: :name,
tooltip: "This is a tooltip" do %>
<%= f.text_field :name,
placeholder: "Name",
class: form_control_classes %>
<% end %>
Find details on all of the customization options you can apply to a form field by checking out the list of local variables in this file:
app/views/shared/components/forms/_field.html.erb
In order to apply Instrumental's styling to Rich Text fields (a.k.a. Trix fields), you'll need to add a few things:
rich_text_field: true
option to the field wrapperdata-controller="components--rich-text"
attribute to the fielddata-action="focus->components--rich-text#focus blur->components--rich-text#unfocus"
attribute to the fieldLike this:
<%= render "shared/components/forms/field",
form: f,
label: "Description",
name: :description,
tooltip: "This is a tooltip",
rich_text_field: true do %>
<%= f.rich_text_area :description,
data: {
controller: "components--rich-text",
action: "focus->components--rich-text#focus blur->components--rich-text#unfocus"
} %>
<% end %>
When displaying a single checkbox field, you should add wrap_label: true
to the field wrapper. The label appears above the field, by default, but when you add wrap_label: true
, the label appears to the right of the field.
<%= render "shared/components/forms/field",
form: f,
label: "I agree to the terms and conditions",
name: :terms_of_service,
wrap_label: true do %>
<%= f.check_box :terms_of_service %>
<% end %>
When displaying a group of checkboxes, you can wrap each of those checkbox fields within another field
partial, like this:
<%= render "shared/components/forms/field",
form: f,
label: "Group label" do %>
<%= render "shared/components/forms/field",
form: f,
label: "I agree to the terms and conditions",
name: :terms_of_service,
wrap_label: true do %>
<%= f.check_box :terms_of_service %>
<% end %>
<%= render "shared/components/forms/field",
form: f,
label: "I agree to the terms and conditions",
name: :terms_of_service,
wrap_label: true do %>
<%= f.check_box :terms_of_service %>
<% end %>
<%= render "shared/components/forms/field",
form: f,
label: "I agree to the terms and conditions",
name: :terms_of_service,
wrap_label: true do %>
<%= f.check_box :terms_of_service %>
<% end %>
<% end %>
The same concept as multiple checkboxes can be applied to radio button groups:
Wrap your group of radio buttons within another field
partial, like this:
<%= render "shared/components/forms/field",
label: "Guitar Type",
description: "This is a description for the guitar type.",
tooltip: "This is a tooltip" do %>
<% Guitar.guitar_types.keys.each do |type| %>
<%%= render "shared/components/forms/field",
form: f,
label: type.titleize,
tooltip: "This is a tooltip for #{type.titleize}",
name: "guitar_type_#{type}",
wrap_label: true do %>
<%= f.radio_button :guitar_type, type %>
<% end %>
<% end %>
<% end %>
To style a selection dropdown, add the select_field: true
option to the field wrapper, like this:
<%= render "shared/components/forms/field",
form: f,
label: "Thing Type",
name: :thing_type,
tooltip: "This is a tooltip",
select_field: true do %>
<%= f.select :thing_type,
Thing.thing_types.keys.map { |type| [type.humanize, type] },
{ include_blank: true },
{ class: "form-control" } %>
<% end %>
Instrumental provides a color picker component, which lets users select a color from a color picker or type in a hex code.
Implement the color picker field by adding:
color_field: true
option to the field wrapperdata-controller="components--color-picker"
attribute to the fieldLike this:
<%= render "shared/components/forms/field",
form: f,
label: "Color",
name: :color,
placeholder: "Color",
color_field: true do %>
<%= f.color_field :color,
data: {
"components--color-picker-target": "colorPicker"
} %>
<% end %>
Instrumental provides an image upload field, which will display the currently saved image and provide a link to delete the image or replace it. It also has special styling to improve the upload button.
First, you can add the image upload field using this code:
<%= render "shared/components/forms/field",
image_upload_field: true,
form: f,
label: "Image",
name: :image,
tooltip: "This is a tooltip",
image_object: @guitar.image,
delete_image_path: remove_guitar_image_path(@guitar) do %>
<%= f.file_field :image,
accept: 'image/*',
data: {
"components--image-upload-target": "input",
action: "components--image-upload#updateImage components--image-upload#revealImagePreview"
} %>
<% end %>
You should also set up a controller action to handle the deletion of the image. That action should look something like this:
<% def remove_guitar_image
@guitar.image.purge
redirect_to edit_guitar_path(@guitar), notice: "Image removed successfully."
end %>
Avatar image upload fields are a slight variation on the image upload field. They show a preview of the avatar image and display a circular version of the current avatar image.
<%= render "shared/components/forms/field",
image_upload_field: true,
avatar_field: true,
avatar_resource: current_user,
form: f,
label: "Avatar",
name: :avatar,
tooltip: "This is a tooltip",
delete_image_path: remove_user_avatar_path do %>
<%= f.file_field :avatar,
accept: 'image/*',
data: {
"components--image-upload-target": "input",
action: "components--image-upload#updateImage components--image-upload#revealImagePreview"
} %>
<% end %>
I created Instrumental Components to make designing and building professional apps with Ruby on Rails easy, fast, and fun. I use it on all of my projects and I hope it helps you build something great.