Getting started
A number of the concepts in Primer Forms are borrowed from the view_component framework. For example, forms are defined inside Ruby classes and rendered using the #render
method.
Let's create a sign up form and render it on the page.
Example for the impatient
class SignUpForm < ApplicationForm form do |sign_up_form| sign_up_form.group(layout: :horizontal) do |name_group| name_group.text_field( name: :first_name, label: "First name", required: true, caption: "What your friends call you." ) name_group.text_field( name: :last_name, label: "Last name", required: true, caption: "What the principal calls you." ) end sign_up_form.text_field( name: :dietary_restrictions, label: "Dietary restrictions", caption: "Any allergies?" ) if @show_notifications_checkbox sign_up_form.check_box( name: :email_notifications, label: "Send me gobs of email!", caption: "Check this if you enjoy getting spam." ) end sign_up_form.submit(label: "Submit") end def initialize(show_notifications_checkbox: true) @show_notifications_checkbox = show_notifications_checkbox endend
Directory structure
Autoloading is automatically enabled for any sub-directory inside a Rails' app's app/ directory. Accordingly, we recommend placing all form classes inside app/forms/.
The directory structure within app/forms/ is arbitrary, but we have seen success using the same directory structure as app/controllers/. For example:
app ╵─ controllers ╵─ settings ╵─ email_notifications_controller.rb ╵─ forms ╵─ settings ╵─ email_notifications ╵─ config_form.rb
ApplicationForm
Our example class above inherits from ApplicationForm
. This follows the Rails convention of a base class that houses application-specific logic common to all forms. It's similar in purpose to ApplicationRecord
and ApplicationController
.
Ultimately, forms must inherit from Primer::Forms::Base
, meaning ApplicationForm
can be as simple as:
class ApplicationForm < Primer::Forms::Base # empty body, add common methods, includes, etc hereend
Place ApplicationForm
in app/forms/application_form.rb
Anatomy of a form
Forms are just Ruby classes that inherit from Primer::Forms::Base
. Define a form's inputs using the form
class method, which accepts a block. The block is called with an instance of Primer::Forms::Dsl::FormObject
, which responds to the following form input methods:
text_field
: Text input field.text_area
: Text area field (multi-line).select_list
: Drop-down select list.check_box
: Single check box.check_box_group
: Group of related check boxes.radio_button_group
: Group of related radio buttons.hidden
: Hidden input.multi
: Multi input (multiple fields that look like a single field).submit
: Submit button.button
: Regular, non-submit button.separator
: Horizontal separator.fields_for
: Used for composing forms together.
Rendering
Forms are rendered using the familiar Rails #render
method:
<%= primer_form_with(model: @user) do |f| %> <%= render SignUpForm.new(f, show_notifications_checkbox: false) %><% end %>
The primer_form_with
helper
You may have noticed the use of the primer_form_with
helper above. This helper is analogous to Rails' form_with
helper, but layers on some additional functionality. It automatically:
- configures the form to use Primer's form builder
- disables Rails' default error markup functionality, which breaks Primer styling
- forces labels to always identify their inputs via the
for
attribute - enables the special handling of
system_arguments
that allows for utility arguments likeml: 2
and friends
It is recommended to always use primer_form_with
instead of form_with
.
The primer_form_for
helper
Before the introduction of #form_with
in Rails 5.1, forms were created using the #form_for
helper. Although #form_for
has since been soft-deprecated, Primer includes the analogous #primer_form_for
for completeness. Prefer #primer_form_with
for new forms.