menu

Forms

Forms provide a way for a user to easily interact with N2 applications.

You can find more information about Forms here.


Overview


API & Demo

To utilize this streamlined form builder that is error handling:

= form_for :resource, builder: MaterialForm do |f|

It can be utilized with form_with to create forms with or without an ActiveRecord model backing it:

= form_with url: resource_path, local: true, builder: MaterialForm do |f|

To set the color for all form inputs, pass it as an option.

= form_for :resource, builder: MaterialForm, color: :cyan do |f|

Disabled fields of most types are not design-approved. Instead you should use the field_with_default_value helper and pass in the `readonly` option.

= form_for @object, builder: MaterialForm do |f|
  # editable select with the list of states
  = f.select :state, states
  # readonly text field instead of a select
  = f.field_with_default_value :state, readonly: true

To make fields disabled based on policy, define read_only predicate methods on the object passed into a form, e.g. read_only_field? for the field attribute. If the field is a checkbox, checkbox collection, or individual radio button, it will be disabled. Otherwise, it will display as a read-only text field.

= form_for @object, builder: MaterialForm do |f|
  = f.text_field :name    # read-only text field if @object.read_only_name? is true
  = f.text_field :address # read-only text field if @object.read_only_address? is true
  = f.select :state, states # read-only text field if @object.read_only_state? is true
  = f.checkbox :local # disabled checkbox if @object.read_only_local? is true
  = f.radio_button :main_address # disabled radio button if @object.read_only_main_address? is true
  = f.collection_check_boxes :times, times # disabled checkboxes if @object.read_only_times? is true
= form_for :resource, builder: MaterialForm, color: :cyan do |f|

To configure default options for all forms in an application, configure with an initializer:

MaterialForm.configure(color: "lime")
# Passing an optional label option overwrites the default label which
# is the specified attribute(name in this case) titleized. Passing the
# length attribute enables a character counter
= f.text_field :name
# If you have a placeholder be sure to pass active: true
= f.text_field :name, label: "Name", placeholder: "type something", active: true
import { Input } from 'n2-styles'

<Input
  id='name'
  type='text'
  label='Name'
  placeholder='type something'
  isActive={true} // forces the label in active state if true
/>
# Assigning a color name as a color attribute will style the input
# for the specified color
# Inputs that respond to colors are:
# text_field, text_area, email_field, number_field, password_field,
# telephone_field, url_field, date_field, time_field, range_field,
# radio_button, check_box, switch, search, md-search, multiple select
= f.text_field :name, color: "red"
# Passing an optional label option overwrites the default label which
# is the specified attribute(text_area in this case) titleized.
# Passing the length attribute enables a character counter
= f.text_area :text_area, length: 120
# Passing an optional label option overwrites the default label which
# is the specified attribute(text_area in this case) titleized.
# Passing the length attribute enables a character counter
= f.text_area :text_area, length: 120, class: "materialize-textarea"
# Passing an optional label option overwrites the default label which
# is the specified attribute(text_area in this case) titleized.
# Passing the length attribute enables a character counter
= f.text_area :text_area, length: 120, class: "no-scroll"
# Passing an optional label option overwrites the default label which
# is the specified attribute(email_field in this case) titleized.
= f.email_field :email_field
import { Input } from 'n2-styles'

<Input
  id='personal-email'
  type='email'
  label='Email'
/>
# Passing an optional label option overwrites the default label which
# is the specified attribute(number_field in this case) titleized.
= f.number_field :number_field
import { Input } from 'n2-styles'

<Input
  id='count'
  type='number'
  label='Count'
/>
# Passing an optional label option overwrites the default label which
# is the specified attribute(password_field in this case) titleized.
= f.password_field :password_field
import { Input } from 'n2-styles'

<Input
  id='password'
  type='password'
  label='Password'
/>
# Passing an optional label option overwrites the default label which
# is the specified attribute(telephone_field in this case) titleized.
= f.telephone_field :telephone_field
import { Input } from 'n2-styles'

<Input
  id='telephone'
  type='tel'
  label='Telephone'
/>
# Passing an optional label option overwrites the default label which
# is the specified attribute(url_field in this case) titleized.
= f.url_field :url_field
import { Input } from 'n2-styles'

<Input
  id='website-url'
  type='url'
  label='Website Url'
/>
# Passing an optional label option overwrites the default label which
# is the specified attribute(date_field in this case) titleized.
# The date needs to be formatted to MaterialForm::DATE_FIELD_FORMAT
# in order for the datepicker to parse an existing date value
= f.date_field :date_field, value: date&.strftime(MaterialForm::DATE_FIELD_FORMAT) #"%b. %-d, %Y"
# Passing an optional label option overwrites the default label which
# is the specified attribute(time_field in this case) titleized.
= f.time_field :time_field, class: "timepicker"
# Passing an optional label option sets a persistent label on the
# top of the select
= f.select :favorite_sport, [["basketball", 1], ["football", 2], ["baseball", 3]]
import { Select } from 'n2-styles'
<Select
  className="browser-default select-wrapper"
  sortField="text"
  options={[["basketball", 1], ["football", 2], ["baseball", 3]]}
  allowCreate={true}
  multiple={true}
  plugins={{position_dropdown_within_viewport: true, remove_button: { label: '', className: 'remove' }}}

See the selects documentation for more information about using selects.

# Passing an optional label option overwrites the default label which
# is the specified attribute(check_box in this case) titleized.
%fieldset.form-group
  = f.check_box :check_box, { label: "Checkbox?" }, "yes", "no", class: "filled-in"
# Passing an optional label option overwrites the default label which
# is the specified attribute(radio_button in this case) titleized.
%fieldset.form-group
  = f.radio_button :radio_button, "yes"
  = f.radio_button :radio_button, "no"

%fieldset.form-group
  = f.collection_radio_buttons :radio_field, %w(Option1 Option2 Option3), :to_s, :to_s

# You can pass an optional `display: "vertical"` option to
# #collection_radio_buttons to stack them vertically
%fieldset.form-group
  = f.collection_radio_buttons :ad_type, AdType.all, :id, :name, { display: "vertical" }, required: true
# Passing an optional label option overwrites the default label which
# is the specified attribute(text in this case) titleized.
= f.text_area :text, label: "This is a label"
Switch
# Behaves very much like a checkbox
= f.switch :email, { label: "Email" }, "yes", "no"
# For use in form_tag
# By default: value is "1", checked is false
= switch_tag(name, label, value = "1", checked = false, options = {})
# Passing an optional label option overwrites the default label which
# is the specified attribute(text in this case) titleized.
= f.range_field :text
File
# Supports the same options that a text field does (hints, labels)
# and handles errors
= f.file_field :file
$
# The currency_field automatically converts it's value to a currency for display
= f.currency_field :price
= f.currency_field :price, value: 120.0
= f.block_check_box :foo, value: bar do
  .d-flex.flex-row.align-items-center.px-4.py-1.w-100.grey.lighten-4.justify-content-between
    .grey-text.text-darken-3 Publication
    .grey-text.text-darken-3 Territory
= f.block_collection_radio_buttons :duration, presenter.duration_options, :last, :first, { checked: f.object.duration } do |box|
  .d-flex.flex-row.align-items-center.px-4.py-1.w-100.grey.lighten-4.justify-content-between= box.text