PHPackages                             anthonyedmonds/laravel-form-builder - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. anthonyedmonds/laravel-form-builder

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

anthonyedmonds/laravel-form-builder
===================================

Create one-thing-per-page forms with forking logic and task lists; ideal for the GOV.UK Design System!

2.2.0(2w ago)11.3k12MITPHPPHP ^8.3

Since Sep 18Pushed 2w ago1 watchersCompare

[ Source](https://github.com/AnthonyEdmonds/laravel-form-builder)[ Packagist](https://packagist.org/packages/anthonyedmonds/laravel-form-builder)[ RSS](/packages/anthonyedmonds-laravel-form-builder/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (10)Dependencies (28)Versions (46)Used By (2)

[![Composer status](.github/composer.svg)](.github/composer.svg)[![Coverage status](.github/coverage.svg)](.github/coverage.svg)[![Laravel version](.github/laravel.svg)](.github/laravel.svg)[![NPM status](.github/npm.svg)](.github/npm.svg)[![PHP version](.github/php.svg)](.github/php.svg)[![Tests status](.github/tests.svg)](.github/tests.svg)

Laravel Form Builder
====================

[](#laravel-form-builder)

Create one-thing-per-page forms broken down into tasks; ideal for the GOV.UK Design System!

What's in the box?
------------------

[](#whats-in-the-box)

- Laravel Form Builder classes, interfaces, and traits
- Basic frontend pages for demonstration and testing purposes

The user interface is left up to you to implement and style as you desire.

Upgrading
---------

[](#upgrading)

Guidance on upgrading versions can be found in the [upgrade guide](docs/upgrading.md).

Installation
------------

[](#installation)

### Composer

[](#composer)

You can install this library using Composer:

```
composer require anthonyedmonds/laravel-form-builder
```

### Service Provider

[](#service-provider)

The Form Builder service provider will be automatically registered.

If you need to manually load it, you can add the following to your `config/app.php` file:

```
'providers' => [
    // ...
    AnthonyEdmonds\LaravelFormBuilder\LaravelFormBuilderServiceProvider::class,
],
```

### Publish files

[](#publish-files)

The following can be published using `php artisan vendor:publish`:

KeyUsageTargetconfigThe Form Builder configuration fileconfig/form-builder.phpviewsThe Form Builder blades and componentsresources/vendor/form-builder/...The configuration file is required for registering forms.

The views are optional, used primarily as a basis for building your own form UI components.

If you are using GOV.UK Laravel, you can switch to the pre-made views by changing the `template` config setting.

### Routes

[](#routes)

Add the Form Builder routes to your `routes/web.php`:

```
Route::laravelFormBuilder();
```

Configuration
-------------

[](#configuration)

The `config/form-builder.php` file contains the following options:

KeyUsageTypeDefaultformsA list of Forms available in the systemclass-string\[\]\[\]templateWhich view template to usestringdefaultStructure
---------

[](#structure)

Each `Form` follows a simple structure, with movement controlled automatically based on the user's choices:

> Form &gt; Start or Resume
>
> Tasks &gt; Task &gt; Question
>
> Summary &gt; Submit or Draft &gt; Confirmation &gt; Exit

1. Upon entering a `Form`, the system will check whether they have an active session
    1. If they do, they will be asked whether they want to resume or start fresh
    2. If not, they will be shown a start page (if enabled)
2. Users will then be shown a list of `Tasks`
    1. They may pick any `Task` to complete, though a `Task` can be disabled if they cannot start it yet
3. Entering a `Task` shows the user the `Question` list
    1. Entering a `Question` allows the user to provide answers to any number of fields
    2. Once all `Question` classes within a `Task` have been answered, they can return to the `Tasks` list
4. Once all `Task` classes have been completed, the user can then view a `Summary` of their answers
    1. They may then submit their answers, or save as a draft (if enabled)
5. After successful submission, users will be shown a confirmation screen (if enabled)
6. Users then exit the `Form`

This library provides all of the flow control basis required, based on the content you provide.

The user's answers are stored in a session directly on the related `Model` as they progress through the `Form`.

A [diagram is available here](./docs/UML%20v3.png) which shows the internal workings.

Setting up a Form
-----------------

[](#setting-up-a-form)

Every Form starts by extending the `Form` class.

As a minimum, you will need to provide a unique `key()` for the Form, the `modelClass()`, and a set of `tasks()`.

You can customise the behaviour of your Form elements by overriding functions in your classes.

### Model

[](#model)

The `Model` to be used with your `Form` must implement the `UsesForm` interface.

The `HasForm` trait is provided to fill in most of the needed functionality.

As a minimum with the trait, you will need to provide a `viewRoute()`.

This will allow users to view their submission after completing the `Form`.

#### Drafts

[](#drafts)

A flag is provided on the `Model` to enable or disable saving as a draft.

If you enable saving as a draft, it is recommended to customise the `saveAsDraft()` function appropriately.

### Tasks

[](#tasks)

Every `Form` is broken up into several `Task` classes.

These are wrapped up in a `Tasks` class.

You can have as many or as few `Task` classes as you like; it is recommended to keep each `Task` to a minimum.

```
public function tasks(): array
{
    return [
         MyTask::class,
         NextTask::class,
         ...
    ];
}
```

As a minimum, you will need to provide a list of `tasks()`.

#### Task Groups

[](#task-groups)

You may group your tasks by providing a keyed array instead:

```
public function tasks(): array
{
    return [
        'Group one' => [
            MyTask::class,
            ...
        ],
        'Group two' => [
            NextTask::class,
            ...
        ],
    ];
}
```

It is not recommended to mix grouped and ungrouped `Task` classes, as this may become visually confusing.

#### Showing and hiding Task classes

[](#showing-and-hiding-task-classes)

You can control which `Task` classes are shown by adding any needed logic to the `tasks()` method.

Users may be confused by the constant appearance and disappearance of tasks, so it is recommended to keep it simple, and consistent.

You may find it is better to have a `Task` in the `Not Required` state, instead of hiding it entirely.

### Start and Confirmation pages

[](#start-and-confirmation-pages)

Flags are provided on the `Form` to control whether to show the `Start` and `Confirmation` pages.

If `Start` is disabled, users will be taken straight to the `Tasks` page.

If `Confirmation` is disabled, users will be taken straight to the `viewRoute()` of the `Model`.

Creating a Task
---------------

[](#creating-a-task)

Each `Task` contains any number of `Question` classes.

As a minimum, you will need to provide a unique `key()`, and a list of `questions()`.

### Statuses

[](#statuses)

Every `Task` has a status based on the status each `Question`.

You can customise the logic of which statuses are shown by overriding the relevant functions on the `Task`.

For more information, see the `HasStates` trait.

### Showing and hiding Questions

[](#showing-and-hiding-questions)

You can control which `Question` classes are shown by adding any needed logic to the `questions()` method.

Users may be confused by the constant appearance and disappearance of questions, so it is recommended to keep it simple, and consistent.

You may find it is better to have a `Question` in the `Not Required` state, instead of hiding it entirely.

Creating a Question
-------------------

[](#creating-a-question)

Each `Question` contains any number of fields, which should directly correspond to attributes on the `Model`.

A `Question` can be used in any number of `Task` classes, especially when abstracted if they are similar.

You can customise how values are read and written to the `Model`; by default, it will use the provided field key.

### Fields

[](#fields)

Every `Question` has one or more `Fields`, which control the inputs shown on the page.

```
[
    Field::input('name', 'What is their name?')
        ->setHint('Provide their full name')
        ->optional(),
]
```

`Field` comes with a helper for each common input type.

In this example, the first parameter is the `name` of the input, which corresponds to the `name` property on the `Model`.

The second parameter is the question being asked.

When there is only one `Field` in a `Question`, it should be used as the page title.

The `hint` method adds a line of supporting text to the `Field`.

The `optional` method marks the `Field` as not required; `Fields` are required by default.

Many other methods are available to further customise the input.

### Customising the Model attribute

[](#customising-the-model-attribute)

Out of the box, `Field` classes use their `name` to determine which `Model` attribute it relates to.

This controls most of Form Builder's automatic behaviour.

You can set an `attribute` property to customise that behaviour.

This can be useful where you have a simple input for a complicated attribute, such as a relationship.

For example, you might ask for an e-mail to find a User, but capture their ID on the `Model`:

```
/** Model with `user` relationship */
$model = new MyModel();

/** Field value will be equal to $model->user?->email */
Field::input('email', 'What is the user\'s e-mail address?')
    ->setAttribute('user.email');
```

### Additional fields

[](#additional-fields)

The `Question` blade has two customisable sections before and after the main `Field`.

These can be used to add additional content to your question blade.

They can be utilised as follows:

```
@extends('form-builder::question')

@section('before-main')
    Example
@endsection

@section('before-fields')
    This is a starting paragraph
@endsection

@section('after-fields')
    This is an ending paragraph
@endsection
```

### Skippable Questions

[](#skippable-questions)

A flag is provided to allow users to skip a question.

This can be useful for optional questions, where it may be clearer that the user does not have to give a response.

If you enable skipping, it is recommended to customise the `applySkip()` function appropriately.

### Looping Questions

[](#looping-questions)

A flag is provided to redirect users back to the same `Question` after saving.

This can be useful for adding multiple responses to the same question.

When doing this, the `Question` should also be skippable, with the skip option being used to progress forward.

If skipping is not enabled, the user will must be provided with a way to move forward.

### Statuses

[](#statuses-1)

Each `Question` has a status based on the user's answers to each field.

You can customise the logic of which statuses are shown by overriding the relevant functions on the `Question`.

For more information, see the `HasStates` trait.

### Clearing Answers

[](#clearing-answers)

Form Builder determines whether a `Question` has been answered by whether the `Model` has a matching `$attribute` key, even if that key is null.

To clear a `Question` as if it had never been answered, you can call `$model->clearAnswer('attribute-key');` to remove the needed keys.

This is often used when changing the answer to an earlier `Question` which should wipe answers elsewhere in the `Form`.

Using and accessing Forms
-------------------------

[](#using-and-accessing-forms)

Users have two main entry points to any `Form`, new and edit.

### Start a new Form

[](#start-a-new-form)

Users can be redirected to the `new` endpoint using any of the following:

- `Model::formRoute()`
- `Model::newForm()->route()`
- `route('forms.new', MyForm::key())`

### Edit an existing Model

[](#edit-an-existing-model)

Users can be redirect to the `edit` endpoint using any of the following:

- `Model::formRoute($model)`
- `$model->form()->editRoute()`
- `route('forms.edit', [MyForm::key(), $model])`

### Pre-filling Form Fields

[](#pre-filling-form-fields)

It may be useful to pre-fill some `Form` `Fields` based on the context of where the `Form` was started.

This can be done by using the URL query string in combination with the `makeForForm()` method on the `Model`.

As an example, to pass the `system` key to the `Form` you could do the following:

1. Call `Model::formRoute()` and append a query string to the URL
    - `/forms/my-form/new?system=blah`
2. Override the `makeForForm()` method on the `Model` to set the desired properties
    - ```
        public static function makeForForm(): UsesForm
        {
            $model = new MyModel();

            if (Request::has('system') === true) {
                $model->system()->associate(
                    Request::input('system'),
                );
            }

            return $model;
         }
        ```

This can be done for as many fields as required, and can save users time.

Viewing models
--------------

[](#viewing-models)

If you would like to use the Form Builder `Summary` page for a viewing a model, you may use the `view()` method on your model.

This will generate a `Summary` style page without the ability to change any answers.

A link back to the `Form` should be included, if the model can be edited.

You can control whether an individual `Question` can be edited by adjusting the `canChange()` method.

Testing
-------

[](#testing)

To assist with the creation of unit tests, an `AssertsForms` trait has been provided.

You can add this to your base `TestCase` class to use the following methods:

AssertionUsageassertField(array $expectations, Field $field)Provide the expected values for the Field, then the field itselfHelp and support
----------------

[](#help-and-support)

You are welcome to raise any issues or questions on GitHub.

If you wish to contribute to this library, raise an issue before submitting a forked pull request.

Licence
-------

[](#licence)

Published under the MIT licence.

###  Health Score

53

—

FairBetter than 96% of packages

Maintenance97

Actively maintained with recent releases

Popularity22

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity64

Established project with proven stability

 Bus Factor1

Top contributor holds 90.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~6 days

Recently: every ~16 days

Total

42

Last Release

16d ago

Major Versions

0.4.4 → 1.0.02025-10-07

1.8.1 → 2.0.02026-03-30

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/17785811?v=4)[Anthony Edmonds](/maintainers/AnthonyEdmonds)[@AnthonyEdmonds](https://github.com/AnthonyEdmonds)

---

Top Contributors

[![AnthonyEdmonds](https://avatars.githubusercontent.com/u/17785811?v=4)](https://github.com/AnthonyEdmonds "AnthonyEdmonds (190 commits)")[![MichaelDono](https://avatars.githubusercontent.com/u/10013030?v=4)](https://github.com/MichaelDono "MichaelDono (16 commits)")[![Tahreem-112](https://avatars.githubusercontent.com/u/176474246?v=4)](https://github.com/Tahreem-112 "Tahreem-112 (2 commits)")[![SimRoberts9](https://avatars.githubusercontent.com/u/124249635?v=4)](https://github.com/SimRoberts9 "SimRoberts9 (1 commits)")

---

Tags

laravelbuilderformquestiongovuktask listone thing per page

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/anthonyedmonds-laravel-form-builder/health.svg)

```
[![Health](https://phpackages.com/badges/anthonyedmonds-laravel-form-builder/health.svg)](https://phpackages.com/packages/anthonyedmonds-laravel-form-builder)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[renatomarinho/laravel-page-speed

Laravel Page Speed

2.5k1.7M10](/packages/renatomarinho-laravel-page-speed)[vinkius-labs/laravel-page-speed

Laravel Page Speed

2.5k12.5k1](/packages/vinkius-labs-laravel-page-speed)[emargareten/inertia-modal

Inertia Modal is a Laravel package that lets you implement backend-driven modal dialogs for Inertia apps.

90142.9k](/packages/emargareten-inertia-modal)[inkvizytor/fluentform

Form builder for Laravel

3416.6k](/packages/inkvizytor-fluentform)[wearepixel/laravel-cart

A cart implementation for Laravel

1374.8k](/packages/wearepixel-laravel-cart)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
