Most HTML5-specific elements are `input` tags with special `type` attributes. For example, `` is an HTML5-spcific data type.
To easily set the `type` tag with an `input` driver, use a pipe character `|`:
```
$form->add('email_address', 'input|email');
$form->email_address->set('driver', 'input|email');
```
## HTML 5 Input types
Use any of the following driver|type combindations:
- input|tel
- input|email
- input|url
- input|date
- input|datetime
- input|datetime-local
- input|color
- input|week
- input|time
- input|month
- input|range
- input|number
## Datalist
```
$opts = [
'run' => 'running',
'jump' => 'jumping',
'crawl' => 'crawling',
'swim' => 'swimming',
'basketball' => 'basketball',
];
$form->add('hobbies', 'datalist', NULL, ['opts' => $opts]);
```
Add class/HTML attributes
## Add and remove classes
To edit the class for a field, use `Formo::add_class()` and `Formo::remove_class()`. They work just like jQuery.
```
$form->email->add_class('foo bar');
$form->email->add_class(['foo', 'bar']);
$form->email->remove_class('foo');
```
To add a class at a field's creation or using `Formo::set()`, note that a field's class exists in `attr['class']`
```
$form->add('email', 'input|email', NULL, ['attr.class' => 'foo bar']);
$form->email->set('attr.class', 'foo bar');
```
## HTML Attributes
HTML attributes can be directly manipulated in Formo objects as well. They exist in the `attr` field attribute.
Ultimately `attr` is an array of HTML attributes.
```
$attr = [
'onclick' => 'doSomething()',
'id' => 'someId',
'placeholder' => 'myplaceholdertext',
'class' => 'foo bar',
];
$form->$field->set('attr', $attr);
```
Because of this, at creation, it is often convenient to just use dot syntax to set a single attribute
```
$form->add('email', 'input|email', NULL, ['attr.placeholder' => 'john@doe.com']);
```
To edit attributes, you can always directly get and set them using `Formo::set('attr' => [])`, `Formo::get('attr.name')` and `Formo::merge('attr', $attrs)`, but it's often easier to use `Formo::attr()`.
The arguments for `Formo::attr()`:
- name
- value (optional, default = NULL)
If you don't specify a second argument, the method will return the attribute for that field.
You can also pass an array of attributes as well.
And to unset an attribute, pass `NULL` as the second parameter.
```
$form->attr('id', 'foobar');
$id = $form->attr('id');
$form->attr('id', NULL);
```
You can also set an array of attributes.
```
$form->attr([
'id' => 'foo',
'class' => 'foobar',
'onclick' => 'do_somethign()',
])
```
## Single attribute tags, such as 'disabled'
For HTML tags that don't require a value, set the value to `true`. Here's an example of disabling a field:
```
$field->set('attr.disabled', true);
// Renders as <tagName disabled...>
```
Checkboxes, Radios, Select
These field types require an `opts` array of `value => label` pairs that are used for the checkboxes, radios and options.
Here, we are creating all three field types from one array.
```
$opts = [
'run' => 'running',
'jump' => 'jumping',
'crawl' => 'crawling',
'swim' => 'swimming',
'basketball' => 'basketball',
];
```
## Select
```
// Select field with 'jump' option selected
$form->add('hobbies', 'select', 'jump', ['opts' => $opts]);
```
For optgroups, use arrays within the `opts` array, like this:
```
$opts = array
(
'on foot' => [
'run' => 'running',
'jump' => 'jumping',
'skip' => 'skipping',
],
'on water' => [
'swim' => 'swimming',
'boat' => 'boating',
'dive' => 'diving',
],
'basketball' => 'basketball',
);
$form->('hobbies', 'select', null, ['opts' => $opts]);
```
## Multiselect
Multiselects work the same as select except you need to modify the `name` attribute and the `multiple` attribute. The main difference here is the value should be an array instead of a string for a multiselect.
Using the select example above, it looks like this
```
$form->add('hobbies', 'select', ['jump'], ['opts' => $opts, 'attr.name' => 'hobbies[]', 'attr.multiple' => true]);
```
## Radios
```
// Radios with 'swim' option selected
$form->add('hobbies', 'radios', 'swim', ['opts' => $opts]);
```
## Checkboxes
```
// Checkboxes with 'jump' and 'swim' selected
$form->add('hobbies', 'checkboxes', ['jump', 'swim'], ['opts' => $opts]);
```
## Single checkbox
```
// Single checkbox checked by default
$form->add('bool_field', 'checkbox', 1);
```
Custom Templates
There are two variables Formo uses to decide which view file to use as a field's template:
- `template_dir`
- `template`
The default `template_dir` is defined in the Formo config.php file.
The `template` variable is defined per-driver (and can also be customized per field or form). When the field renders, Formo finds a view file named `$template_dir/$template`.
In the view, Formo passes a single variable named `$field` which is either the form or field object. To customize your form, set these files, then create custom HTML that looks the way you want it.
Here's an example of styling a form by changing all the template directories.
```
$form->set('template_dir', 'my_special_form');
foreach ($form->get('fields') as $field)
{
$field->set('template_dir', 'my_special_form');
}
```
Or just set a template for a specific field that has complicated styling.
```
$form->complicated_field->set('template', 'complicated_template');
```
It's also easy to set a template for a specific form.
```
$form->set('template', 'my_form_template');
```
Optional Subforms
It's common to have an entire subform that needs to be validated as a whole subform under specific situations.
A typical situation goes like this:
```
- Enter mailing address
- Choose whether shipping address is different from mailin address
- If so, enter shipping address
```
Consider the situation above. The second form has a bunch of validation rules that only matter at all if the user selected 'shipping address is different from mailing address.'
You can do this with Formo subforms.
Here's an example
```
$form = Formo::form();
$form->mailing_address = Formo::form()
->add('city', 'input', null, ['rules' => [['not_empty']]])
->add('state', 'input', null, ['rules' => [['not_empty']]])
->add('zip', 'input', null, ['rules' => [['not_empty']]]);
$form->add('different_shipping_address', 'checkbox');
$form->shipping_address = Formo::form()
->add('city', 'input', null, ['rules' => [['not_empty']]])
->add('state', 'input', null, ['rules' => [['not_empty']]])
->add('zip', 'input', null, ['rules' => [['not_empty']]]);
$form->add('submit', 'input|submit', 'save')
->load($this->request->post());
if ($form->mailing_address->validate())
{
}
if ($form->different_shipping_address->val() AND $form->address2->validate())
{
}
```
You can see it's not difficult to validate an entire subform based on meeting certain criteria.