Skip to content


Our Forms package is designed to give developers to freedom to build forms via classes and set the fields in those classes comfortably. You can easily pass a form to a view and it will render the whole form, reducing your need to type out divs, labels, inputs and more.

Source Code

Forms by default is set to Bootstrap's classes, but you can change these in the config.

Artisan Commands

Generate a form for a specific model using this make command. It will add the ModelForm to a Forms directory in the app/Html/Forms namespace.

artisan make:model-form {model}

Generate a generic form with a specific name using this command. It will add the BaseForm to a Forms directory in the app/Html/Forms namespace.

artisan make:base-form {name}

The following command will generate a feature test which hits the endpoints of the form.

artisan make:form-test {form}

If you made a ModelForm you likely want a factory for your model, since we have the fields within the ModelForm class we can generate basic factories.

artisan make:form-factory {form}

Set Alternate Connections


Or in the UserForm itself:

$connection = 'alternate';

Blade Directives

Form Maker only has one blade directive and that is for handling any assets you may add to a field. In the case of the Quill field we load the CDN assets (javascript and css), and we inject a snippet of JavaScript. These assets need to be rendered in your view. Ideally this is done close to the closing body tag of your main template.


Just place that below any of your JavaScript file references and you can easily load the forms field assets when the Form is being rendered on screen.

Blade Components

If you like to keep your blade files looking a little nicer you can also use Blade Components. This lets you reduce the use of curly braces everywhere.

<x-f :content="$form"></x-f>


form() // access the `Form` class


Fields are PHP objects which define types, options, attributes etc for the Form Object. This lets you design forms and update them easily via a single object rather than having to update HTML files for multiple roles in your application.

type: A type string such as text or file
options: Options for <select> type
format: Format for DateTime objects
legend: A label for the legend of horizontal checkboxes
null_value: False by default, but allows empty values to be placed at the front of selects
null_label: Text which is placed as the first option in a select with a blank value
value: If you set the value of a field it will fill it in, or select it in the case of selects
label: A string or false (if you want the label blank - useful for `legend` uses)
model: Model class for the HasOne and HasMany Fields
model_options: Model options
    label: The label attribute on the model
    value: The value attribute on the model
    method: A custom method to run on the model
    params: Parameters to send to the custom method
before: Text or HTML you wish to put before an input
after: Text or HTML you wish to put after the input
view: A view path to a custom template
template: A custom template with some basic key value swaps
attributes: HTML attributes for your input field
factory: The type of input faker to use for test generating
assets: The js, styles, scripts, and stylesheets values

There are a large collection of Fields available out of the box and a make:field {name} command in case you need custom ones. Fields generate a config array which is then processed by the FieldMaker and FieldBuilder to create forms for easy use.

Available Fields

Any fields that include JS should have zero dependencies. Those that require jQuery obviously require jQuery.

Boostrap/Toggle (includes JS, requires jQuery)
Boostrap/Select (includes JS, requires jQuery)
Boostrap/HasOne (includes JS, requires jQuery)
Boostrap/HasMany (includes JS, requires jQuery)
Boostrap/Suggest (includes JS, requires jQuery)
Attachments (includes JS, requires jQuery)
Code (includes JS)
Datepicker (includes JS)
Dropzone (includes JS)
FileWithPreview (includes JS)
Quill (includes JS)
Slug (includes JS)
Tags (includes JS)
Typeahead (includes JS, requires jQuery)

Special Field Options

Some fields have extra options which pertain to their configs. Below are more custom options you can apply to these special fields.


See for more options.

theme: "light|dark"
on: "On"
off: "Off"
size: "sm"
btn: "btn-primary"
btn: "btn-primary"
btn: "btn-primary"
btn: "btn-primary"

See for more options.

mode: "htmlmixed"
theme: "default"

See for more options

theme: "light"
background-color: "#FFF"
color: "#FFF"
number-color: "#111"
highlight: "var(--primary, "#EEE")"
header: "var(--primary, "#EEE")"
start-day: 1
format: "YYYY-MM-DD"
theme: "light"
queue-complete: "function () { window.location.reload() }"
upload-multiple: true
route: ""
file_size: "25MB"
process_url: null
submit-button: "button[type="submit"]"
upload_result_field: null
preview_identifier: "" // class or ID for an avatar img or div
preview_as_background_image: false
theme: "light"
quill_theme: "snow"
toolbars: [
upload_route: "upload.image"


If you want to use images inside Quill you need to have a route which can handle the image uploads. Storing images as data-urls (Quill default method) is never wise. The following is an example of a Controller invoke method which can handle the file uploads.

$validatedData = $request->validate([
    'file' => 'image|required',

$path = collect($validatedData)->first()->store('public/uploads');

return response()->json([
    'data' => [
        'success' => true,
        'path' => str_replace('public', 'storage', url($path)),
default-border: "#EEE"
focus-border: "#EEE"
matches: []

Field Assets

Out of the box Forms comes with a few fields which contain field assets. You can add assets to any field, and the Forms package will collect them and put links to them where you use the blade directive forms. We suggest below your app.js link on your master blade file.

In order to add assets to a field you need to use the following protected methods: stylesheets, scripts, styles, js. The following is an example from the Quill field.

protected static function stylesheets($options)
    return [

protected static function scripts($options)
    return ['//'];

// This was added for demo purposes
protected static function styles($id, $options)
    return <<<EOT
#$id {
    color: #FFF;

protected static function js($id, $options)
    $theme = $options['theme'] ?? 'snow';
    $placeholder = $options['placeholder'] ?? '';

    return <<<EOT
    new Quill('#$id', {
        theme: '$theme',
        placeholder: '$placeholder'


By default for any form assets all JS and CSS is minified in production using We keep in unminified locally and in testing for easier debugging.

Default JS Validation

In general based on form submissions - we return a nice looking form with the error labels in place. The annoying part would be writing JavaScript validation per input to clean up the UI from the form return. If you set php-inline public $withJsValidation = true; then you'll get a handy vanilla JS injection which removes the invalid classes on keyup or focus out.


The various Form Objects allow you to set Sections. For example, you may have a BlogForm and you may want one row to have three columns while the next row has two, this can be achieved with the setSections method.

$columns = 1;

public function fields()
    return [
        Text::make('title', [
            'required' => true,
        Text::make('url', [
            'required' => true
        TextArea::make('entry', []),
        Date::make('published_at', []),

By default this will build a form with single column content. If you wish to set these fields to specific layouts you need to set the columns to sections

$columns = 'sections';

public function fields()
    return [
        Text::make('title', [
            'required' => true,
        Text::make('url', [
            'required' => true
        TextArea::make('entry', []),
        Date::make('published_at', []),

public function setSections()
    return [

The above will produce a form that is two columns, one, and one. You can add a key to the sections to add a horizontal line and a header.

public function setSections()
    return [
        'Content' => [

HTML Snippets

Within the fields section of the Form Object you can also place some HTML snippets. These can help with spacing and UI layouts. The Snippets included in Forms are:


All of these snippets can have the class attribute set. Div and Heading can also have content set in them.


The Form class lets us generate simple forms with minimal code.

form()->action('method', 'route', 'button text', $html_attributes);

Generates a form using the method and route with a button, for easier addition of delete buttons and more.

You can also provide a payload to action forms similar to the confirm below:

form()->payload(['user' => $user->id])->action(...);

form()->confirm('Are you sure?')->action(...);
Adds a confirmation popup to the button.

confirm is only supported in the delete method of ModelForms.

If you wish to handle the confirm using a modal or other JS integration you can pass a method name into the confirm method which will trigger that JS method:

form()->confirm('Are you sure you want to delete this?', 'confirmation')->action(...);

This will add the following to the submit button in the form:

onclick="confirmation(event, 'Are you sure you want to delete this?')"

You will require a confirmation method to be defined somewhere such as in app.js. Your confirmation method could look something like this, which uses Bootstrap's modal:

window.confirmation = (_event, _message) => {


        show: true

    $('#appModalConfirmBtn').click(() => {

    return false;

There is also support for an submitMethod attribute on all forms. This custom submit allows you to override the standard submit and perform actions against your form. This can be useful if you want to do an ajax submission of your form.


namespace App\Http\Forms;

use Grafite\Forms\Fields\Password;
use Grafite\Forms\Forms\BaseForm;

class UserSecurityForm extends BaseForm
    public $route = '';

    public $method = 'put';

    public $orientation = 'horizontal';

    public $submitMethod = 'ajax';

    public $buttons = [
        'submit' => 'Save',

    public $columns = 1;

    public function fields()
        return [
            Password::make('old_password', [
                'required' => true,
                'label' => 'Old Password'
            Password::make('new_password', [
                'required' => true,
                'label' => 'New Password'
            Password::make('new_password_confirmation', [
                'required' => true,
                'label' => 'Confirm New Password'
window.ajax = (_event) => {

    let _form =;
    let _method = _form.method.toLowerCase();
    let _payloadArray = $(_form).serializeArray();
    let _payload = {};

    $.map(_payloadArray, function(n, i){
        _payload[n['name']] = n['value'];

    window.axios[_method](_form.action, _payload)
        .then((response) => {
        .catch((error) => {

            for (var key in {

Opens a form allowing you to specify options: action, method, attributes etc.

form()->model($model, $options);

Open a form based on a model


In general all classes are defined in the config, which means you can avoid Boostrap if you want to. You can also set the form class directly on the form itself.

public $formClass = 'form';

Any classes set on the form, or field itself will override the default configs. The following are default configs:

'buttons' => [
    'submit' => 'btn btn-primary',
    'delete' => 'btn btn-danger',
    'cancel' => 'btn btn-secondary',

'form' => [
    'class' => 'form',
    'delete-class' => 'form-inline',
    'inline-class' => 'form d-inline',

    'group-class' => 'form-group',
    'input-class' => 'form-control',
    'label-class' => 'control-label',
    'label-check-class' => 'form-check-label',
    'before_after_input_wrapper' => 'input-group',
    'text-error' => 'text-danger',
    'error-class' => 'has-error',
    'check-class' => 'form-check',

    'check-input-class' => 'form-check-input',
    'check-inline-class' => 'form-check form-check-inline',
    'custom-file-label' => 'custom-file-label',
    'custom-file-input-class' => 'custom-file-input',
    'custom-file-wrapper-class' => 'custom-file',

    'sections' => [
        'column-base' => 'col-md-',
        'row-class' => 'row',
        'full-size-column' => 'col-md-12',
        'header-spacing' => 'mt-2 mb-2',
        'row-alignment-between' => 'd-flex justify-content-between',
        'row-alignment-end' => 'd-flex justify-content-end',

    'orientation' => 'vertical',
    'horizontal-class' => 'form-horizontal',
    'label-column' => 'col-md-2 col-form-label pt-0',
    'input-column' => 'col-md-10',


Using the make:model-form {model} command you can quickly generate forms for Models. This will let you generate forms based on the model.




namespace App\Http\Forms;

use App\Models\Role;
use App\Models\User;
use Grafite\Forms\Fields\File;
use Grafite\Forms\Fields\Text;
use Grafite\Forms\Fields\Email;
use Grafite\Forms\Fields\Checkbox;
use Grafite\Forms\Forms\ModelForm;

class UserForm extends ModelForm
    public $model = User::class;

    public $routePrefix = 'user';

    public $buttons = [
        'submit' => 'Save',

    public $columns = 1;

    public $orientation = 'horizontal';

    public $hasFiles = true;

    public function fields()
        return [
            Text::make('name', [
                'required' => true,
            Email::make('email', [
                'required' => true
            Checkbox::make('dark_mode', [
                'legend' => 'Dark Mode'
            File::make('avatar', []),

Within this UserForm class you can set the fields in in the fields method:

public function fields()
    return [
        Text::make('name', [
            'required' => true,
        Email::make('email', [
            'required' => true

This will generate a form with these fields only. You can also set the orientation if you wish to use labels on the left side instead of above and columns if you wish to generate a form in which the fields are split into more columns.

$routePrefix is required as it defines the routes using route names which match the standards route naming of Laravel.

$hasFiles enables the file submission of the form.

$buttons enables you to customize the button values for submit and cancel

$buttonClasses enables you to customize the button class values for submit, cancel, and delete which can also be done in the config as form default

$confirmMessage lets you set the confirm message for the delete button

$confirmMethod sets the method name for the onclick event when clicking on the delete button

With the delete() form you can also add the confirmation method like so:

{!! form()
    ->confirm('Are you sure you want to delete your avatar?', 'confirmation')
    ->action('delete', 'user.destroy.avatar', 'delete', ['class' => 'btn btn-sm btn-outline-secondary'])

Accessing the Model Instance

You can access the model instance in a model form, it can give you the freedom to collect data from the model in the case of setting select values etc.

public $instance;

You can also check if its been set by running:


Custom View for Fields

You can create a custom view that the Forms will use for your fields. Just have you view file follow this pattern:

<div class="row">
    <div class="form-group">
        {!! $label !!}
        <div class="row">
            {!! $field !!}
    {!! $errors !!}

    {!! $options !!}

The values passed to the view are label, field, errors, options. The options is how you can pass more abstract configs through, but in all honesty we dont really see many use cases of that.

Custom Template for Fields

You can create a custom template that the Forms will use for your fields. This way you do not need a view file. Templates have a VERY basic templating component to them.

You have the following variables that are passed to the template:

Template Key What it Is
{id} The field ID
{name} The label
{errors} An HTML string of error messages
{label} The label as an HTML string
{field} The field as an HTML string
{rowClass} The CSS class which wraps around the label and field
{labelClass} The CSS class which is on the label
{fieldClass} The CSS class which is on the field

This has value when using horizontal forms vs vertical forms.

<div class="{rowClass}">
    <label for="{id}" class="{labelClass}">{name}</label>
    <div class="{fieldClass}">


Forms also has Fields called HasOne and HasMany. These enable you to select one or multiple from a relationship binding in your model.

For example you may have a User who has a role which is belongsToMany.

You can set the Field for something like 'Roles' as below.

HasOne::make('role', [
    'model' => Role::class,
    'model_options' => [
        'label' => 'name',
        'value' => 'id',
        'method' => 'all',
        'params' => null,

You can also customize how you access the method and with what parameters. By default it will try to collect the options by getting Role::all() however you can limit that with something like Role::custom(params).

With a ModelForm you can also utilize the index and search methods. This lets you render full index tables of models and search forms for those models. There are also some special properties you can set on your ModelForm in order to optimize the index and allow some fields to be sortable.

$with is used as a portion of the model query run in index listing.

$paginate allows you to set a number for how many items to load in the index.


In case you wish to output the index to an API call.


Renders a search form for the model index

app(UserForm::class)->index()->search('', 'placeholder', 'Button Text', 'form-method');

Field Options

Each field by default will be listed in the index. You can customize this by setting the visible option to false.

If you wish to make a field sortable (asc|desc) then you can set the sortable option to true.

Custom Query on Index

You can also pass a query into the index method if you wish to set some details.

$query = User::whereIn('in', [1, 2, 3]);