outhebox/nova-hidden-field
A Laravel Nova field that hides attributes from forms and detail views while still submitting and storing their values. Declare defaults for auto-filled or sensitive data, keep the UI clean, and persist values without custom JavaScript or resource workarounds.
Architecture fit. The package is a single Nova custom field: one PHP class extending Nova's base Field, plus a trivial (or effectively absent) Vue component that renders an <input type="hidden"> inside the resource form. It participates in Nova's standard field lifecycle — resolve, fill, hydrate — so it composes with fields(), fieldsForCreate(), fieldsForUpdate(), rules(), and fillUsing() exactly like a first-party field. There is no service provider surface, no config file, no migration, and no published assets. Architecturally this is the right shape: it adds a field type, not an abstraction. The corollary a TPM should hold onto is that the package's entire value is roughly 30–60 lines of code a Nova-competent engineer could reproduce in a pairing session. Treat it as tooling inventory, not a platform dependency, and size the decision accordingly.
Integration feasibility. Mechanically trivial and fast: composer require outhebox/nova-hidden-field, import the class, drop it into a resource's fields(). Effort is measured in minutes; the real budget line is verification, not implementation. The critical constraint is that laravel/nova is not distributed via Packagist, so Composer has no visibility into Nova's version and cannot block an incompatible install. Any adoption plan must therefore front-load a one-hour spike — create a field, load the form, confirm no "unknown component" console warning, confirm the hidden input exists in the DOM, and confirm the value actually persists on create — and treat that spike as the go/no-go gate rather than a formality.
Technical risk. The risk profile is asymmetric: small upside, potentially material downside, and it concentrates in three places.
->default() never reaches the request and the column is written as null. That class of bug surfaces weeks later as orphaned foreign keys in production data, which is a data-quality incident, not a dependency incident.fillUsing, model observer, or service) and validated with rules().Secondary risks worth logging: documentation drift (the summary implies conditional/reactive visibility that the code does not implement — plan against the code, not the copy), and the fact that Nova actions, nova:run, imports, seeders, and direct API writes bypass the field entirely.
Key questions for the team before adoption.
hideWhenCreating() / hideWhenUpdating() / onlyOnDetail() combined with ->default() satisfies a meaningful share of "hidden field" requests, and duplicating framework behaviour is pure liability.Stack fit. Requires Laravel + Laravel Nova. It is a back-office-only concern: Nova resources are the internal admin surface, not the customer product. If a roadmap item is phrased "let an operator create X from within Y's admin screen," this field is a candidate implementation detail; if it touches a customer-facing flow, it is out of scope by construction. Note the package is Nova-only — it does nothing for API write paths, queued jobs, or non-Nova admin surfaces.
Migration path. Two routes, and the recommendation depends on the spike result rather than on the package's merits:
composer require, register the field where needed, standardise the pattern (ownership/tenant stamping, attribution metadata, slug-from-title, workflow status defaults) across the eligible resources. No migration, no config publish, no asset build.src/Hidden.php and the Vue component into our codebase under our namespace, own it, and move on. The escape hatch costs an afternoon, which is precisely why lock-in is a non-issue and why "is this vendor good?" is the wrong question.Either way, the pattern survives even if the dependency doesn't. That's the strategic point: we are evaluating a 30-line idiom, and the fork is a first-class outcome, not a fallback.
Compatibility. Unproven and unprovable by Composer. Sequence compatibility verification strictly before anything else, and record the result per Nova major so the next team doesn't re-litigate it. If we run multiple Nova versions across apps, prove it per version — a pass on one app is not a pass on the estate.
Sequencing.
fillUsing / rules() conventions) across remaining resources.Maintenance. Effectively zero upstream maintenance and therefore zero upstream maintenance assurance — no releases since 2020, no issue triage guarantee, no patch channel. Our operational cost is not upgrading the package; it is (a) the hour spent proving compatibility per Nova upgrade, and (b) the eventual fork when a Nova major breaks it. Budget the fork as a known future cost, not a risk. MIT licence with an auditable code surface keeps this cheap.
Support. No vendor, no SLA, no maintainer commitment. Internal support is whatever the adopting team assigns. Because the code is small, first-line support is "read the class" — but that requires someone who has read it once. Name that person.
Scaling. Scales fine in the only dimension that matters here: adding the field to more resources is a one-line change per resource, and there is no runtime overhead, no query cost, no background processing, and no shared state. The scaling limit is organisational, not technical — the more resources use it, the more surface area depends on an unmaintained package, which strengthens the case for vendoring early rather than late. There is no per-user or per-request cost profile to plan against.
Failure modes and detection. Rank by consequence, then instrument accordingly:
->default() never reaches the request; the column is written null. Detection: a not-null constraint or a scheduled integrity query on the stamped columns, plus a smoke test in the release checklist that asserts the value round-trips on create. Do not rely on users noticing.->default() not reapplying on update. Common surprise for developers expecting model-event semantics. If a value must be recomputed each save, use fillUsing(). Detection: it shows up as stale attribution data, usually in reporting.->rules('required') on a hidden field fails for Nova actions or any path where the component didn't render. Prefer sometimes / nullable unless every render path is confirmed.hideFromCreate() / onlyOnDetail() / hideWhenCreating() prevent mounting, so the default never ships. Hidden does not mean omitted.Ramp-up. Near zero for a developer: one import, one line in fields(), and a skim of the class. The genuine ramp-up is the convention — when to use the hidden field versus a model observer versus fillUsing, and the standing rule that invariants never live in the browser. Write that down as a short internal note alongside the adoption decision so the next engineer doesn't rediscover it via a null foreign key. Total onboarding cost: under an hour, once, shared across the team.
Recommendation for the decision memo. Timebox a one-hour compatibility spike. If it clears, adopt on internal resources where a missing value degrades gracefully, and vendor the class as soon as more than a couple of resources depend on it. If it fails, fork it rather than reject the pattern. Either way, record that the package is a convenience for the Nova UI path only, that server-side derivation remains the control of record, and that the published description overstates its capabilities.
How can I help you explore Laravel packages today?