PHPackages                             lupennat/nested-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. [Utility &amp; Helpers](/categories/utility)
4. /
5. lupennat/nested-form

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

lupennat/nested-form
====================

Laravel Nova - Nested Form

v1.5.0(2y ago)034.4k↓30.5%MITVuePHP ^7.4|^8.0

Since May 23Pushed 2y ago2 watchersCompare

[ Source](https://github.com/Lupennat/nested-form)[ Packagist](https://packagist.org/packages/lupennat/nested-form)[ RSS](/packages/lupennat-nested-form/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (3)Versions (7)Used By (0)

this repository will no longer have updates, a new version of the package is available [here](https://github.com/Lupennat/nova-nested-many)

1. [Requirements](#Requirements)
2. [Installation](#Installation)
3. [Usage](#Usage)
4. [DependsOn](#dependson)
5. [Additional options](#additional-options)
    1. [Prefill](#prefill)
    2. [Custom Heading](#custom-heading)
6. [Credits](#credits)

Requirements
------------

[](#requirements)

- `php: ^7.4 | ^8`
- `laravel/nova: ^4`

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

[](#installation)

```
composer require lupennat/nested-form

```

Usage
-----

[](#usage)

Simply add a NestedForm into your fields. The first parameter must be an existing NovaResource class and the second parameter (optional) must be an existing HasOneOrMany relationship in your model.

> NestedForm is visible by deafult on DetailPage, UpdatePage and CreatePage. NestedForm is not available on IndexPage.

```
namespace App\Nova;

use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Gravatar;
use Laravel\Nova\Fields\Password;
// Add use statement here.
use Lupennat\NestedForm\NestedForm;

class User extends Resource
{
    ...
    public function fields(Request $request)
    {
        return [
            ID::make()->sortable(),

            Gravatar::make(),

            Text::make('Name')
                ->sortable()
                ->rules('required', 'max:255'),

            Text::make('Email')
                ->sortable()
                ->rules('required', 'email', 'max:254')
                ->creationRules('unique:users,email')
                ->updateRules('unique:users,email,{{resourceId}}'),

            Password::make('Password')
                ->onlyOnForms()
                ->creationRules('required', 'string', 'min:6')
                ->updateRules('nullable', 'string', 'min:6'),

            // Add NestedForm here.
            NestedForm::make('Posts'),
        ];
    }
```

Depends On
----------

[](#depends-on)

NestedForm support Nova `dependsOn`.

```
NestedForm::make('Posts', Post::class)
    ->dependsOn('name', function(NestedForm $field, NovaRequest $novaRequest, FormData $formData) {
        if ($formData->name === 'xxx') {
            $field->min(1)->max(10);
        }
    })
```

it also support a short version of dependsOn without callback

```
NestedForm::make('Posts', Post::class)->dependsOn('name')
```

Both syntax will propagate the condition to related resource, you can access propagated content adding `HasNestedForm` trait on your related resource.

```
use Lupennat\Nova\Resource;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;
use Lupennat\NestedForm\HasNestedForm;

class Posts extends Resource
{

    use HasNestedForm;

    public function fields(Request $request)
    {
        return array_filter([
            ID::make(),
            BelongsTo::make(__('User'), 'user', User::class),
            Select::section(__('Section'), 'section')->options(['sport' => 'Sport', 'news' => 'News'])->rules('required'),
            Text::title(__('Title'), 'title')->rules('required'),
            $this->canShowExtra() ? Text::make(__('Extra Field'), 'extra')->hide() : null
        ]);
    }

    protected function canShowExtra() {
        if (
            $this->getNestedFormParentResource() === User::uriKey() &&
            $this->getNestedFormParentContent('name') === 'xxx'
        ) {
            return true;
        }

        return false;
    }
}
```

Additional options
------------------

[](#additional-options)

functiondescriptiondefault`->max(int)`limit number of related resources allowed0`->min(int)`minimum number of related resources0`->lock()`disable add and remove related resourcesfalse`->prefill(array,bool)`[prefill](#prefill) related resources with values\[\], false`->useTabs()`switch display mode to tabs instead of panelsfalse`->activeTab(int)`set default active tab by index0`->activeTabByHeading(string)`set default active tab by 'heading'null`->canDuplicate()`enable duplicate resource buttonfalse`->canRestore()`enable soft delete on resource when deleted (only vue)false`->addText(string)`text for add button"add $resourceName"`->restoreText(string)`text for restore button"restore $resourceName"`->removeText(string)`text for remove button"remove $resourceName"`->duplicateText(string)`text for duplicate button"duplicate $resourceName"`->heading(string, boolean)`define [custom heading](#custom-heading)\[\], false`->separator(string)`define heading separator" . "### Prefill

[](#prefill)

You can use `prefill` method to generate a default set of related resource.

> Prefill works only on Create Page

```
NestedForm::make('Posts', Post::class)
    ->prefill([
        ['title' => 'first post', 'section' => 'sport'],
        ['title' => 'second post', 'section' => 'news'],
    ])
```

You can force prefill to always respect the numbers of prefilled items through a second boolean parameter.

```
NestedForm::make('Posts', Post::class)
    ->prefill([
        ['title' => 'first post', 'section' => 'sport'],
        ['title' => 'second post', 'section' => 'news'],
    ], true)
```

### Custom Heading

[](#custom-heading)

By Default NestedForm Heading is:

- DetailPage `${resourceName} ${keyName}: ${resource[keyName]}`
- UpdatePage exists `${resourceName} ${keyName}: ${resource[keyName]}` new `${index} ${separator} ${resourceName}`
- CreatePage `${index} ${separator} ${resourceName}`

You can specify a Custom Heading using resource fields value, defining attribute names, through `heading` method, the second parameter of the method specify if the heading should be "unique".

When a custom heading is defined, the fields are hidden on the panel, but when the user try to add a new resource a modal with required fields is displayed; if unique is true, NestedForm will check to existing related resource the uniqueness of the fields. Multiple fields value will be concatened by the defined separator.

```
NestedForm::make('Posts', Post::class)
    ->heading(['section', 'title'], true)
    ->separator(' - ')
```

---

Credits
=======

[](#credits)

NestedForm field is based on original [Nova Nested Form](https://github.com/yassilah/laravel-nova-nested-form).

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity28

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 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.

###  Release Activity

Cadence

Every ~4 days

Total

6

Last Release

1071d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3cea30d9041841dbfc768dc8b690c0cf4fb3244073f9edaf08f9c8f9d04f470a?d=identicon)[lupennat](/maintainers/lupennat)

---

Top Contributors

[![Lupennat](https://avatars.githubusercontent.com/u/6160171?v=4)](https://github.com/Lupennat "Lupennat (10 commits)")

---

Tags

laravelnova

###  Code Quality

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/lupennat-nested-form/health.svg)

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

###  Alternatives

[eminiarts/nova-tabs

Laravel Nova - Tabs.

4624.1M20](/packages/eminiarts-nova-tabs)[outl1ne/nova-sortable

This Laravel Nova package allows you to reorder models in a Nova resource's index view using drag &amp; drop.

2861.8M9](/packages/outl1ne-nova-sortable)[sbine/route-viewer

A Laravel Nova tool to view your registered routes.

57215.9k](/packages/sbine-route-viewer)[markwalet/nova-modal-response

A Laravel Nova asset for Modal responses on an action.

14720.0k](/packages/markwalet-nova-modal-response)[datomatic/nova-enum-field

A Laravel Nova PHP 8.1 enum field with filters

20134.2k](/packages/datomatic-nova-enum-field)[norman-huth/nova-assets-changer

Change Nova resources

2570.1k](/packages/norman-huth-nova-assets-changer)

PHPackages © 2026

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