PHPackages                             fewagency/fluent-form - 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. fewagency/fluent-form

AbandonedArchivedLibrary

fewagency/fluent-form
=====================

Fluent interface style HTML Form generator

2801[6 issues](https://github.com/bjuppa/fluent-form/issues)PHP

Since Oct 17Pushed 7y ago4 watchersCompare

[ Source](https://github.com/bjuppa/fluent-form)[ Packagist](https://packagist.org/packages/fewagency/fluent-form)[ RSS](/packages/fewagency-fluent-form/feed)WikiDiscussions master Synced today

READMEChangelogDependenciesVersions (1)Used By (0)

[Fluent interface](https://en.wikipedia.org/wiki/Fluent_interface) HTML form builder for PHP
============================================================================================

[](#fluent-interface-html-form-builder-for-php)

An extension to [fluent-html](https://github.com/fewagency/fluent-html)for building accessible, well-formated, yet customizable HTML forms.

```
// Generate a simple inline search form
echo FluentForm::create()
    ->inline()
    ->containingInputBlock('query', 'search')
    ->followedByButtonBlock('Search!');
```

```

Query

Search!

```

- [Installation](#installation--configuration)
- [Principles](#principles)
- [Usage](#usage)
- [Alternatives](#alternatives)
- [Authors - FEW Agency](#authors)
- [License](#license)

Installation &amp; configuration
--------------------------------

[](#installation--configuration)

> composer require fewagency/fluent-form

### Optional facades

[](#optional-facades)

You may add [Laravel facades](http://laravel.com/docs/facades) in the `aliases` array of your project's `config/app.php` configuration file:

```
'FluentForm'  => FewAgency\FluentForm\Facades\FluentForm::class,
```

Principles
----------

[](#principles)

A `FluentForm` consists of [*control blocks*](src/AbstractControlBlock.php), grouped within [*control block containers*](src/AbstractControlBlockContainer.php). The base `FluentForm` element is such a container together with `FieldsetElement`, an example of a nested container. `InputBlock` and `CheckboxBlock` are examples of control blocks.

### Control blocks

[](#control-blocks)

Control blocks contain between one and three elements, in this order:

1. The label wrapper is used for holding the control's label. The label wrapper is not always present, e.g. for blocks containing checkbox inputs wrapped in their own labels.
2. The form control wrapper is present on all control blocks and holds the actual form control. In some cases several form controls may be present within the control wrapper.
3. The descriptive element is present only if the form control has a description or messages to show to the user.

### Control block containers

[](#control-block-containers)

Many control properties can be set on the container level, affecting the form controls within that container. These properties are first checked on an individual element and if not specified there we check upwards in the HTML tree, through the control block, its block containers, up to the `` element itself. This makes it easy to set and override properties in sections of a form.

### Method names

[](#method-names)

Naming principles are based upon [those of the base-package `fewagency/fluent-html`](https://github.com/fewagency/fluent-html#naming-principles). Some examples of methods in this package returning a new element relative the current one are the `containing...Block()` methods found on control block containers, and `followedBy...Block()` methods of control blocks.

### CSS class names

[](#css-class-names)

This package uses the [BEM approach for CSS naming](http://getbem.com/naming/).

Usage
-----

[](#usage)

`FluentForm::create()` is the base for a new form.

Form controls can be named and referenced with dot-notation. A control named `person.name` will have its `name` attribute rendered as `person[name]`.

The `name` attribute of a control named `pets` will be rendered with appended empty brackets (`pets[]`) if the input is a "multiple" input.

Keep in mind most methods accept collections and closures as parameters as in any [`fewagency/fluent-html` usage](https://github.com/fewagency/fluent-html#usage).

Depending on where you want your form HTML output you may `echo FluentForm::create()->...;`or render it using PHP string conversion, i.e. `(string)FluentForm::create()->...`.

Within [Blade](http://laravel.com/docs/blade) templates, the HTML will be rendered if placed in echo-tags: `{{ FluentForm::create()->... }}`. Check out the [Blade documentation of `fewagency/fluent-html`](https://github.com/fewagency/fluent-html#usage-with-blade-templates)for more info.

### Convenience methods on forms

[](#convenience-methods-on-forms)

`withAction($url)` sets the `action` attribute of the ``.

`withMethod($method, $name = '_method')` changes the `method` attribute on the `` (default is `POST`). If `$method` is not `GET` or `POST` this will help creating form method spoofing using a hidden input, which is useful for those `PUT`, `PATCH`, or `DELETE` actions.

`withToken($token, $name = '_token')` adds a hidden token input for your CSRF-protection.

```
// Form with options
echo FluentForm::create()
    ->withAction('/login')
    ->withMethod('DELETE')
    ->withToken('12345');
```

```

```

Any other desired attributes or behaviour on the form element can be set using [`FluentHtml`'s standard methods](https://github.com/fewagency/fluent-html#methods-reference)like `withAttribute()` and `withClass()`.

### Add form controls

[](#add-form-controls)

The first control on a form (or other container) is added with one of the `containing...Block()` methods, for example `containingInputBlock($name, $type = 'text')`. This call will return the new block so you can chain any methods modifying that new block directly afterwards.

Subsequent controls are added after another control block using the `followedBy...Block()` methods, for example `followedByInputBlock($name, $type = 'text')`.

#### Block types and their parameters:

[](#block-types-and-their-parameters)

- `...InputBlock($name, $type = 'text')`
- `...PasswordBlock($name = 'password')`
- `...SelectBlock($name, $options = null)`
- `...MultiSelectBlock($name, $options = null)`
- `...ButtonBlock($button_contents, $type = 'submit')`
- `...CheckboxBlock($name)`

#### Adding control blocks example

[](#adding-control-blocks-example)

```
// Form with controls
echo FluentForm::create()
    ->containingInputBlock('username')->withLabel('Your username')
    ->followedByPasswordBlock()->withLabel('Your password');
```

```

Your username

Your password

```

#### Common control block options

[](#common-control-block-options)

`withLabel($html_contents)` adds contents to the control block's labeling element. If not called, the default label will be based on the input's name.

`withInputValue($value)` is available on most control blocks and will set the main underlying input's value directly.

`withInputAttribute($attributes, $value = true)` is available on most control blocks and will set attributes directly on the main underlying input element. Here's a neat trick to format the input's value attribute (the example is using [Carbon](http://carbon.nesbot.com) to format a date-time):

```
->withInputAttribute('value', function($input) {
  $value = $input->getValue();
  try {
    $value = \Carbon\Carbon::parse($value)->toW3cString();
  } catch(Exception $e) {
    // Do nothing on errors
  }
  return $value;
})
```

`withDescription($html_contents)` adds descriptive content related to the input using `aria-describedby`.

```
// Element with description
echo FluentForm::create()
    ->containingInputBlock('name')->withDescription('Your full name');
```

```

Name

Your full name

```

`disabled($disabled = true)`, `readonly($readonly = true)`, and `required($required = true)`sets the relevant HTML attribute on the form control and a corresponding CSS class on the control block.

`withSuccess($has_success = true)` sets a CSS class on the control block element.

`withError($messages)` and `withWarning($messages)`put message lists in the input's descriptive element and a CSS class on the control block. Added error messages also sets the `aria-invalid` attribute on the input element.

```
// Element with error message
echo FluentForm::create()
    ->containingInputBlock('name')->withError('Must not contain numbers');
```

```

Name

Must not contain numbers

```

#### Control types and options

[](#control-types-and-options)

##### Text inputs

[](#text-inputs)

`InputBlock($name, $type = 'text')` generates any `` specified by `$type`, including `textarea`.

Some types get special treatments:

- `password` won't print the `value` attribute unless you specifically set it on the input element.
- `email` and `tel` have some preset `autocapitalize`, `autocorrect`, and `autocomplete` attributes that you are free to override using `withInputAttribute()`.

##### Checkboxes

[](#checkboxes)

`CheckboxBlock($name)` is a checkbox input with a default `value` attribute of "1".

`withInputValue($value)` can be used to set a custom `value` on the checkbox.

`checked($checked = true)` and `unchecked()` manipulates the `checked` attribute on the underlying inputs.

More checkboxes can be added using `withCheckbox($name)` or `containingCheckbox($name)`. The first checkbox is treated as the block's main input, so extra checkboxes won't have any messages or descriptions displayed automatically.

```
// Checkboxes
echo FluentForm::create()
    ->containingCheckboxBlock('toc')->required()->unchecked()
    ->withCheckbox('other');
```

```

Toc

Other

```

##### Select controls

[](#select-controls)

`SelectBlock($name, $options = null)` can be easily turned into a multiselect using `multiple($multiple = true)`.

The `$options` (any collection of option display strings keyed by option value) can be provided on creation or added later through `withOptions($options)`.

``s can be generated by putting a collection of options keyed by an optgroup label within `$options`.

Options are selected using `withSelectedOptions($options)` and disabled using `withDisabledOptions($options)`.

```
// Select with optgroup, disabled and selected options
echo FluentForm::create()
    ->containingSelectBlock('pet')->withSelectedOptions('dog')->withDisabledOptions('cat')
    ->withOptions(['cat' => 'Cat', 'Reptiles' => ['turtle' => 'Turtle'], 'dog' => 'Dog']);
```

```

Pet

Cat
Turtle
Dog

```

##### Buttons

[](#buttons)

`ButtonBlock($button_contents, $type = 'submit')` is a block containing one button from start.

More buttons can be added using `withButton($button_contents, $type = "submit")` or `containingButton($button_contents, $type = "submit")`. The first button is treated as the block's main input, so extra buttons won't have any messages or descriptions displayed automatically.

```
// Buttons
echo FluentForm::create()
    ->containingButtonBlock('Submit')
    ->withButton('Reset', 'reset');
```

```

Submit
Reset

```

#### Custom HTML in blocks

[](#custom-html-in-blocks)

Sometimes you'll want to do special things to the HTML elements within your control blocks.

Here are some methods that can be used to pull out elements on different blocks:

- `getInputElement()`
- `getMainButtonElement()`
- `getMainCheckboxElement()`
- `getLabelElement()`
- `getDescriptionElement()`

Via those elements you can add and modify HTML, both within and around, using the [methods of `FluentHtmlElement`](https://github.com/fewagency/fluent-html#methods-reference).

After doing customizations, you may find yourself deep into a branch of "normal" `FluentHtmlElement`s, outside of the elements of this package. You can find your way back up to the form block or container through [`FluentHtmlElement`'s structure navigation methods](https://github.com/fewagency/fluent-html#methods-for-structure-navigation). `getAncestorInstanceOf(\FewAgency\FluentForm\AbstractControlBlock::class)`or `getAncestorInstanceOf(\FewAgency\FluentForm\AbstractControlBlockContainer::class)`may be especially useful.

```
// Custom HTML next to input
echo FluentForm::create()
    ->containingInputBlock('test')
    ->getInputElement()->followedByElement('span','extra content')
    ->getAncestorInstanceOf(\FewAgency\FluentForm\AbstractControlBlock::class)
    ->followedByInputBlock('after');
```

```

Test

extra content

After

```

### Container options

[](#container-options)

On a control block container, default options can be set that are used for any descendant form controls.

`withValues($map)` adds key-value maps used for populating inputs' values and selected options. If given a PHP object, input values will be pulled from that object's public properties. These maps are checked in order, from the last to the first one added, until a matching key is found. For example you can first add a map of default values, like the currently stored data, and then add a map containing the user's last input.

`withLabels($map)` adds key-value maps for populating inputs' labels.

`withErrors($messages)` and `withWarnings($messages)` adds messages keyed by control name.

To set *success*, *disabled*, *readonly*, or *required* states on controls within a container, use `withSuccess($map)`, `withDisabled($map)`, `withReadonly($map)`, and `withRequired($map)`. Input to those methods can be strings of control names or key-boolean maps keyed by control name.

```
// Adding maps to containers
FluentForm::create()
    ->withSuccess('name', 'phone')
    ->withRequired(['name' => true, 'phone' => false]);
```

To add a hidden input, simply call `withHiddenInput($name, $value = null)` on the container.

#### Laravel form options example

[](#laravel-form-options-example)

```
{{
FluentForm::create()
  // Put the Laravel CSRF token on the form
  ->withToken(csrf_token())
  // Use default values from an Eloquent model, and old user input if flashed into session
  ->withValues($model, old())
   // Add Laravel validation errors to the form
  ->withErrors($errors)
  // Pick default labels from the validation language file
  ->withLabels(trans('validation.attributes'))
}}
```

Adding an [Eloquent model](https://laravel.com/docs/eloquent) to `withValues()` will access the model's values through its [array representation](https://laravel.com/docs/eloquent-serialization), meaning only visible properties will be used in the form. Should you want to expose all attributes of an Eloquent model in the form without making them visible in array and json-representations, `$model->getAttributes()` can be supplied to `withValues()`.

#### Container layouts

[](#container-layouts)

##### Inline form layout

[](#inline-form-layout)

Calling `inline($inline = true)` on a container will turn all its form control blocks and wrappers into `` and does it's best avoiding any block-display HTML elements inside. Not all form controls are suitable for inline display, use it at your own discretion. CSS classes are also added for styling of inline forms.

Any descriptive elements containing messages related to form controls, are grouped and displayed before the inline content, still referenced using `aria-describedby` for good accessibility.

##### Aligned form layout

[](#aligned-form-layout)

Horizontally aligning labels with their form-controls is configured on a container using `aligned($align = true)`. An aligned section will render any wrappers of labels and form controls as `` and add CSS classes for styling. Without any styling, labels and inputs will just display next to each other on the same line, the actual aligning has to be done in CSS.

Any descriptive elements containing messages related to form controls are kept in block-display HTML after the input.

The default CSS classes for alignment can be overridden on each block container using `withAlignmentClasses($classes1, $classes2, $classes3, $offset_classes2, $offset_classes3 = null)`. The `offset...` classes are printed whenever a preceding column is not displayed, e.g. for checkboxes that don't have a label wrapper as the first element of their control block.

#### Nested containers

[](#nested-containers)

On any form block container, like a ``, the method `containingFieldset()` can be used to add and return a nested form block container. On any form block, `followedByFieldset()` can be called with similar effect.

The fieldset can be treated as a regular form block container, but it also has `withLegend($html_contents)`to add contents to its ``.

To add more control blocks outside a nested block container, use `getControlBlockContainer()` on the last item, and then `followedBy...Block()`. Or `getForm()` and then `containing...Block()` if you want to go all the way up adding more blocks to the top container.

```
// Fieldset
echo FluentForm::create()
    ->containingFieldset()->withLegend('A Group')
    ->containingInputBlock('inside')
    ->getControlBlockContainer()
    ->followedByInputBlock('outside');
```

```

A Group

Inside

Outside

```

Alternatives
------------

[](#alternatives)

 is another fluent-style form-generator with major differences being it is more tightly integrated with Laravel, and it is fluent only per input, not the whole form.

Authors
-------

[](#authors)

I, Björn Nilsved, created this package while working at [FEW](http://fewagency.se).

###  Health Score

17

—

LowBetter than 8% of packages

Maintenance0

Infrequent updates — may be unmaintained

Popularity13

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% 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.

### Community

Maintainers

![](https://www.gravatar.com/avatar/c7d75e38113b7a075f11d2d715ab47987cb6f37d6758d111d65858aaf44fe4a5?d=identicon)[bjuppa](/maintainers/bjuppa)

---

Top Contributors

[![bjuppa](https://avatars.githubusercontent.com/u/5339269?v=4)](https://github.com/bjuppa "bjuppa (245 commits)")

---

Tags

form-html

### Embed Badge

![Health badge](/badges/fewagency-fluent-form/health.svg)

```
[![Health](https://phpackages.com/badges/fewagency-fluent-form/health.svg)](https://phpackages.com/packages/fewagency-fluent-form)
```

PHPackages © 2026

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