Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Dependency Container Laravel Package

alexwenzel/nova-dependency-container

Adds dependency containers to Laravel Nova forms, letting you show or hide groups of fields based on the value of another field. Define conditional logic once and keep complex forms clean, reactive, and free of hand-written JavaScript.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin in one step.

composer require alexwenzel/nova-dependency-container
composer show laravel/nova            # confirm the Nova major you are actually on

There is no service provider to register and no config to publish — the package's provider calls Nova::script()/Nova::style() and the compiled component lives in vendor/alexwenzel/nova-dependency-container/dist/. If dist/ is missing from the tarball you own a build step; check that before writing any code.

Three places to look first, in order:

  1. vendor/alexwenzel/nova-dependency-container/README.md — the API surface is ~10 lines of example, and that is the whole doc.
  2. src/DependencyContainer.php — the dependsOn() signature you actually have, not the one the README implies.
  3. src/DependencyContainerItem.php — the single-field wrapper, so you don't have to write a one-element array.

First use case — wrap the fields that only apply to one option of a Select:

use Alexwenzel\DependencyContainer\DependencyContainer;

public function fields(NovaRequest $request): array
{
    return [
        Select::make('Plan', 'plan')->options([
            'basic'   => 'Basic',
            'premium' => 'Premium',
        ])->rules(['required']),

        DependencyContainer::make([
            Number::make('Seat Count', 'seat_count'),
            Text::make('Billing Contact', 'billing_contact'),
        ])->dependsOn('plan', 'premium'),
    ];
}

Load an edit screen for a record that already holds values in seat_count and billing_contact, then toggle plan. Confirm four things before you build a second one: the container renders, the fields save, the fields hydrate on reload, and the container disappears cleanly when you switch back to basic. That round-trip is the real acceptance test — plain rendering tells you almost nothing.

Implementation Patterns

Extract blocks into methods, not inline arrays. A container plus its fields is a unit; keep it addressable and reusable:

protected function premiumBlock(): DependencyContainer
{
    return DependencyContainer::make([
        Number::make('Seat Count', 'seat_count'),
        Text::make('Billing Contact', 'billing_contact'),
    ])->dependsOn(self::FIELD_PLAN, Plan::PREMIUM);
}

Reference the watched attribute through a constant shared with the Select::make(). The most common production defect in this package is a dependsOn('plann', ...) typo — it fails open, renders nothing, logs nothing, and only a reviewer catches it.

Closure conditions for anything richer than equality. Value equality covers the majority of admin screens; in_array and "not empty" cases need the callback form:

DependencyContainer::make([...])
    ->dependsOn('plan', fn ($value) => in_array($value, ['premium', 'enterprise'], true));

If two independent fields must gate one block, verify the array/closure signature against src/ rather than assuming — multi-field support has changed shape across versions, and getting it wrong is silent.

Pair every container with conditional validation. This is the pattern that makes the package safe, and it is your responsibility, not the package's. Hidden fields are still processed by Nova's rules:

Text::make('Billing Contact', 'billing_contact')
    ->rules([
        Rule::when(
            fn () => $request->input('plan') === 'premium',
            ['required', 'string', 'max:255'],
            ['nullable'],
        ),
    ]);

Write this once as a house rule (Rule::when for required, sometimes/nullable for optional) and apply it in review to every container. It converts a per-resource judgement call into a checklist and closes the single most likely support ticket: "the form won't save and I can't see why."

Use DependencyContainerItem when only one field is conditional. It keeps the call site honest about intent and avoids a one-element array that looks like a copy-paste error to the next reader:

DependencyContainerItem::make(
    Text::make('VAT Number', 'vat_number')
)->dependsOn('entity_type', 'company');

Nest deliberately, and shallowly. Containers can hold containers, and it works, but two levels is the practical ceiling before the form becomes untestable. Cap it by convention and write the cap down; otherwise the conditional surface area across a dozen resources grows with no forcing function.

Test the field array, not the browser. fields() is a pure function of the request. A feature test that asserts the container exists and carries the right dependsOn meta catches the typo class of bug in CI, where a Dusk test only catches it after someone clicks:

$fields = collect((new CompanyResource($company))->fields(NovaRequest::create('/')));
$this->assertNotNull($fields->first(fn ($f) => $f instanceof DependencyContainer));

Migrate by rewriting, not porting. Coming from onlyOnForms()/hideFromIndex() toggles or hand-rolled Nova.booting components is authoring work: each condition becomes a container declaration with its own review. Budget a verification pass on records that already hold values in the now-conditional fields — hydration is where regressions surface.

Roll out in three steps. One non-critical resource in a sandbox branch (go/no-go), then a second resource with different field types (proves the pattern generalises), then standardise with the validation convention as the review standard. Hold at step three until the Nova 5 answer and the vendoring decision are settled.

Gotchas and Tips

Hidden ≠ not required. The container hides fields visually; Nova's validation, resolve, and fill still run over them. Nothing in the package changes this. Plan for it in every container you write, and enforce real business rules in a FormRequest or policy, not in the form definition where the API can bypass it.

Silent no-render is the failure mode. A mistyped attribute name, or a value type that doesn't match, produces a container that simply never appears — no console error, no log line. Mitigate with review convention (shared constants, as above), not runtime tooling.

Type mismatch between field and comparison. Select returns strings; Boolean returns real booleans; BooleanGroup and multi-selects return arrays; Number may give you int. '0', 0, '', and null are all distinct and all occur in practice. Use true on the in_array strict flag and dump the actual value once per field type before trusting an equality condition.

Order matters for the operator, not the engine. The container is only discoverable if the parent field is visible above it. Put the Select first in the fields() array; a container that appears above its trigger reads as a layout bug even when the logic is correct.

Index and detail views. The container itself carries no value, but the fields inside it don't automatically know to stay off the index. Confirm what renders on index/detail and constrain explicitly if needed — a stray column is a small bug that looks like carelessness.

Debug via the payload, not the browser. The dependsOn configuration ships to the front end as field meta. Inspect the edit endpoint's JSON response (or dd() the field's meta) to confirm the attribute name and expected value arrived intact; that separates "wrong config" from "component not registered" in one step. If a field renders blank rather than absent, suspect asset registration instead — check /nova-api asset requests and that dist/ is being served.

Extension points are thin by design. Pass-through modifiers (->help(), ->withMeta()) apply to the container, not the contained fields — configure the fields inside it. Don't try to make the container carry rules, defaults, or resolveUsing; give those to the field that owns the value. Keeping the container purely presentational is what keeps a rendering bug from becoming a data bug.

Nesting and hydration interact. If an inner container's field holds a value while the outer container is hidden, Nova will still write whatever the request carries. Normalise on save (null out fields belonging to inactive branches) if the downstream reporting cares about "does this record have a seat count" — otherwise you accumulate orphaned values that look like data-integrity bugs.

Pin, constrain, and treat as vendorable. One maintainer, 46 stars, zero dependents, last release March 2025. Constrain the Nova major in composer.json, pin the package version, and keep nothing else depending on its behaviour. MIT makes forking into an internal registry cheap; budget ~4–8 hours per Nova upgrade cycle for validation either way.

Nova 5 is an open question, not an assumption. The package hooks Nova's internal form-field layer, which shifts between majors. Treat Nova-5 readiness as unresolved until a spike proves it, and let the fork be the mitigation.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package