# Forms
HTML forms are in practice the most used way to interact with a user.
SilverStripe provides classes to generate and handle the actions and data from a
form.
## Overview
A fully implemented form in SilverStripe includes a couple of classes that
individually have separate concerns.
* Controller—Takes care of assembling the form and receiving data from it.
* Form—Holds sets of fields, actions and validators.
* FormField —Fields that receive data or displays them, e.g input fields.
* FormActions—Often submit buttons that executes actions.
* Validators—Validate the whole form.
Depending on your needs you can customize and override any of the above classes;
the defaults, however, are often sufficient.
## The Controller
Forms start at the controller. Here is a simple example on how to set up a form
in a controller.
**Page.php**
:::php
class Page_Controller extends ContentController {
private static $allowed_actions = array(
'HelloForm'
);
// Template method
public function HelloForm() {
$fields = new FieldList();
$actions = new FieldList(
FormAction::create("doSayHello")->setTitle("Say hello")
);
$form = new Form($this, 'HelloForm', $fields, $actions);
// Load the form with previously sent data
$form->loadDataFrom($this->request->postVars());
return $form;
}
public function doSayHello($data, Form $form) {
// Do something with $data
return $this->render();
}
}
The name of the form ("HelloForm") is passed into the `Form` constructor as a
second argument. It needs to match the method name.
Because forms need a URL, the `HelloForm()` method needs to be handled like any
other controller action. To grant it access through URLs, we add it to the
`$allowed_actions` array.
Form actions ("doSayHello"), on the other hand, should _not_ be included in
`$allowed_actions`; these are handled separately through
`Form->httpSubmission()`.
You can control access on form actions either by conditionally removing a
`FormAction` from the form construction, or by defining `$allowed_actions` in
your own `Form` class (more information in the
["controllers" topic](/topics/controllers)).
**Page.ss**
:::ss
<%-- place where you would like the form to show up --%>
$HelloForm
Be sure to add the Form name 'HelloForm' to your controller's $allowed_actions
array to enable form submissions.
You'll notice that we've used a new notation for creating form fields, using
`create()` instead of the `new` operator. These are functionally equivalent, but
allows PHP to chain operations like `setTitle()` without assigning the field
instance to a temporary variable. For in-depth information on the create syntax,
see the [Injector](/reference/injector) documentation or the API documentation
for `[api:Object]`::create().
## The Form
Form is the base class of all forms in a SilverStripe application. Forms in your
application can be created either by instantiating the Form class itself, or by
subclassing it.
### Instantiating a form
Creating a form is a matter of defining a method to represent that form. This
method should return a form object. The constructor takes the following
arguments:
* `$controller`: This must be an instance of the controller that contains the
form, often `$this`.
* `$name`: This must be the name of the method on that controller that is
called to return the form. The first two arguments allow the form object
to be re-created after submission. **It's vital that they be properly
set—if you ever have problems with a form action handler not working,
check that these values are correct.**
* `$fields`: A `[api:FieldList]` containing `[api:FormField]` instances make
up fields in the form.
* `$actions`: A `[api:FieldList]` containing the `[api:FormAction]` objects -
the buttons at the bottom.
* `$validator`: An optional `[api:Validator]` for validation of the form.
Example:
:::php
// Controller action
public function MyCustomForm() {
$fields = new FieldList(
EmailField::create("Email"),
PasswordField::create("Password")
);
$actions = new FieldList(FormAction::create("login")->setTitle("Log in"));
return new Form($this, "MyCustomForm", $fields, $actions);
}
## Subclassing a form
It's the responsibility of your subclass's constructor to call
:::php
parent::__construct()
with the right parameters. You may choose to take $fields and $actions as
arguments if you wish, but $controller and $name must be passed—their values
depend on where the form is instantiated.
:::php
class MyForm extends Form {
public function __construct($controller, $name) {
$fields = new FieldList(
EmailField::create("Email"),
PasswordField::create("Password")
);
$actions = new FieldList(FormAction::create("login")->setTitle("Log in"));
parent::__construct($controller, $name, $fields, $actions);
}
}
The real difference, however, is that you can then define your controller
methods within the form class itself. This means that the form takes
responsibilities from the controller and manage how to parse and use the form
data.
**Page.php**
:::php
class Page_Controller extends ContentController {
private static $allowed_actions = array(
'HelloForm',
);
// Template method
public function HelloForm() {
return new MyForm($this, 'HelloForm');
}
}
**MyForm.php**
:::php
class MyForm extends Form {
public function __construct($controller, $name) {
$fields = new FieldList(
EmailField::create("Email"),
PasswordField::create("Password")
);
$actions = new FieldList(FormAction::create("login")->setTitle("Log in"));
parent::__construct($controller, $name, $fields, $actions);
}
public function login(array $data, Form $form) {
// Authenticate the user and redirect the user somewhere
Controller::curr()->redirectBack();
}
}
## The FormField classes
There are many classes extending `[api:FormField]`. There is a full overview at
[form field types](/reference/form-field-types).
### Using Form Fields
To get these fields automatically rendered into a form element, all you need to
do is create a new instance of the class, and add it to the `FieldList` of the
form.
:::php
$form = new Form(
$this, // controller
"SignupForm", // form name
new FieldList( // fields
TextField::create("FirstName")->setTitle('First name'),
TextField::create("Surname")->setTitle('Last name')->setMaxLength(50),
EmailField::create("Email")->setTitle("Email address")->setAttribute('type', 'email')
),
new FieldList( // actions
FormAction::create("signup")->setTitle("Sign up")
),
new RequiredFields( // validation
"Email", "FirstName"
)
);
## Readonly
You can turn a form or individual fields into a readonly version. This is handy
in the case of confirmation pages or when certain fields cannot be edited due to
permissions.
Readonly on a Form
:::php
$myForm->makeReadonly();
Readonly on a FieldList
:::php
$myFieldList->makeReadonly();
Readonly on a FormField
:::php
$myReadonlyField = $myField->transform(new ReadonlyTransformation());
// shortcut
$myReadonlyField = $myField->performReadonlyTransformation();
## Custom form templates
You can use a custom form template to render with, instead of *Form.ss*
It's recommended you do this only if you have a lot of presentation text or
graphics that surround the form fields. This is better than defining those as
*LiteralField* objects, as it doesn't clutter the data layer with presentation
junk.
First you need to create your own form class extending Form; that way you can
define a custom template using a `forTemplate()` method on your Form class.
:::php
class MyForm extends Form {
public function __construct($controller, $name) {
$fields = new FieldList(
EmailField::create("Email"),
PasswordField::create("Password")
);
$actions = new FieldList(FormAction::create("login")->setTitle("Log in"));
parent::__construct($controller, $name, $fields, $actions);
}
public function login(array $data, Form $form) {
// Do something with $data
Controller::curr()->redirectBack();
}
public function forTemplate() {
return $this->renderWith(array($this->class, 'Form'));
}
}
`MyForm->forTemplate()` tells the `[api:Form]` class to render with a template
of return value of `$this->class`, which in this case is *MyForm*. If the
template doesn't exist, then it falls back to using Form.ss.
*MyForm.ss* should then be placed into your *templates/Includes* directory for
your project. Here is an example of basic customization:
:::ss
`$Fields.dataFieldByName(FirstName)` will return the form control contents of
`Field()` for the particular field object, in this case `EmailField->Field()` or
`PasswordField->Field()` which returns an `` element with specific markup
for the type of field. Pass in the name of the field as the first parameter, as
done above, to render it into the template.
To find more methods, have a look at the `[api:Form]` class and
`[api:FieldList]` class as there is a lot of different methods of customising
the form templates. An example is that you could use `<% loop $Fields %>`
instead of specifying each field manually, as we've done above.
### Custom form field templates
The easiest way to customize form fields is adding CSS classes and additional attributes.
:::php
$field = TextField::create('MyText')
->addExtraClass('largeText');
->setAttribute('data-validation-regex', '[\d]*');
Will be rendered as:
:::html
Each form field is rendered into a form via the
`[FormField->FieldHolder()](api:FormField)` method, which includes a container
`