When building frontend apps, Grind has a handy HTML provider that provides html and form builder objects to your views.

As Grind’s HTML provider was ported from Laravel, these docs were ported from Laravel’s docs as well.

First, add the grind-html package via your preferred package manager:

yarn add grind-html

Next, you’ll need to add HtmlProvider to your app providers in app/Boostrap.js:

import Grind from 'grind-framework'
import { HtmlProvider } from 'grind-html'
const app = new Grind()

{{ form.open({ url: 'foo/bar' }) }}
{{ form.close() }}

By default, a POST method will be assumed however, you are free to specify another method:

{{ form.open({ url: 'foo/bar', method: 'put' }) }}

Since HTML forms only support POST and GET, PUT and DELETE methods will be spoofed by automatically adding a _method hidden field to your form.You may also open forms that point to named routes:

{{ form.open({ route: 'route.name' }) }}

You may pass in route parameters as well:

{{ form.open({ route: [ 'route.name', user.id ] }) }}

If your form is going to accept file uploads, add a files option to your array:

{{ form.open({ url: 'foo/bar', files: true)) }}

Often, you will want to populate a form based on the contents of a model. To do so, use the form.model method:

{{ form.model(user, { route: [ 'user.update', user.id ]}) }}

Now, when you generate a form element, like a text input, the model’s value matching the field’s name will automatically be set as the field value. So, for example, for a text input named email, the user model’s email attribute would be set as the value. However, there’s more! If there is an item in the Session flash data matching the input name, that will take precedence over the model’s value. So, the priority looks like this:

  1. Session Flash Data (Old Input)
  2. Explicitly Passed Value
  3. Model Attribute Data

This allows you to quickly build forms that not only bind to model values, but easily re-populate if there is a validation error on the server!

When using form.model, be sure to close your form with form.close!

{{ form.label('email', 'E-Mail Address') }}

{{ form.label('email', 'E-Mail Address', { class: 'awesome' }) }}

After creating a label, any form element you create with a name matching the label name will automatically receive an ID matching the label name as well.

{{ form.text('username') }}
{{ form.textarea('body') }}

{{ form.text('email', 'example@gmail.com') }}

{{ form.hidden('id', 10) }}

{{ form.password('password') }}

{{ form.email(name, value, attributes) }}
{{ form.file(name, attributes) }}

{{ form.checkbox('name', 'value') }}
{{ form.radio('name', 'value') }}

{{ form.checkbox('name', 'value', true) }}
{{ form.radio('name', 'value', true) }}

{{ form.number('name', 'value') }}

{{ form.file('image') }}

The form must have been opened with the files option set to true.

{{ form.select('size', { L: 'Large', S: 'Small' }) }}

{{ form.select('size', { L: 'Large', S: 'Small' }, 'S') }}

{{ form.select('animal', {
  Cats: { leopard: 'Leopard' },
  Dogs: { spaniel: 'Spaniel' },
}) }}

{{ form.selectRange('number', 10, 20) }}

{{ form.selectMonth('month') }}

{{ echo form.submit('Click Me!') }}

Need to create a button element? Try the button method. It has the same signature as submit.