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 Html Field Laravel Package

think.studio/nova-html-field

A Laravel Nova field for rendering custom HTML content in your admin panel. Use it to display formatted text, links, or embedded markup in forms and detail views, with simple configuration for Nova resources.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Nova custom field, so the only real prerequisite is a working Laravel app with Nova installed. Because the package has zero stars and no dependents, do a two-minute audit before you build on top of it.

1. Check compatibility first. Nova fields are tightly coupled to the Nova major (Vue 2 on Nova 3, Vue 3 on Nova 4/5). Open the package's composer.json and read the require block:

composer require think.studio/nova-html-field
cat vendor/think.studio/nova-html-field/composer.json   # look for laravel/nova constraint
ls vendor/think.studio/nova-html-field/src              # find the Field class name
ls vendor/think.studio/nova-html-field/resources/js      # confirm compiled assets exist

If the nova constraint pins an old major, or the repo has no compiled dist/ assets, stop and treat this as a fork-and-own component rather than a drop-in dependency.

2. Register the field. Nova's package auto-discovery should register the service provider. If the field class isn't resolvable, add the provider listed under extra.laravel.providers to config/app.php and run php artisan config:clear. Confirm the resolved field class name from src/ — the description only calls it "Nova HTML Field", and the actual import (use ThinkStudio\NovaHtmlField\...) matters.

3. First use case: an informational block with no database column. The highest-value, lowest-risk usage is not persisting HTML at all — it's rendering a read-only notice into a resource form or detail screen. This is where you get value in five minutes, with no migration, no column, and no XSS surface:

use ThinkStudio\NovaHtmlField\Html; // verify exact namespace in src/

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),

        Html::make('Billing notice')
            ->html('<p class="text-sm">Invoices are generated on the 1st. Contact finance@… for disputes.</p>')
            ->onlyOnDetail(),

        Text::make('Name'),
        // …
    ];
}

The field supports three content sources — a raw string, a Blade view, or a closure — so the same construct covers static copy, a partial you want to reuse across resources, and dynamic text (e.g. a computed "last synced" note). Start with the static-string variant; it's the one you can reason about without reading the source.

Implementation Patterns

Pattern: read-only guidance injected into forms. The most common day-to-day use is dropping contextual help between two real fields — a banner above a Key::make() file upload, a warning under a Boolean::make() toggle. Because the field takes no column, you don't touch the model, the migration, or the resource's fields() persistence; it renders purely on the UI side. Use ->onlyOnForms() or ->onlyOnDetail() so the same resource doesn't render the block everywhere.

Pattern: Blade view as the single source of truth. Instead of inlining HTML strings across resources, pass a view name so the markup lives in resources/views/nova/... where it can be reviewed, styled with your admin CSS, and versioned alongside the rest of your templates:

Html::make('Onboarding')
    ->view('nova.notices.onboarding', ['user' => $request->user()])
    ->onlyOnDetail();

This is also the seam you want for swapping the package out later — your markup isn't trapped in a ->html() string inside a resource class.

Pattern: closure for dynamic status. Closures let you render state that depends on the authenticated user or a model at render time. This is where the field earns its keep — a cheap "dashboard card" inside a detail view showing counts, sync status, or links, without building a full Nova card or metric:

Html::make('Account status')
    ->closure(fn () => view('nova.notices.status', [
        'count' => $this->unresolvedTickets(),
    ]))
    ->onlyOnDetail();

Keep closures cheap — see the gotchas on index-context queries.

Pattern: wrap writes in sanitization if the HTML is ever user-editable. The field itself is a renderer, not a sanitizer. If any of the content comes from a Textarea/Trix field or an ops-team editor, sanitize at write time with an allowlisted library (e.g. mews/purifier) and store clean HTML — do not rely on the field to strip <script> or onerror=. The field's own escaping/sanitization toggles (whatever they're named in this package) are a second line of defense for trusted HTML, not a substitute for a policy.

Pattern: reuse across resources. Because the field is just a Nova field, you can factor the shared blocks into a small helper or a static method on a Notices class and spread the field definition across resources. That keeps the coupling to this package in one file — which is exactly what you want for a dependency you may have to replace.

Pattern: index-context usage is rare but supported. The field advertises index-context rendering, so you can surface a tiny HTML snippet in a resource table. In practice, prefer ->hideFromIndex() unless you really want markup in a table cell — the value is almost always low and the payload cost is real.

Gotchas and Tips

  • The license is NOASSERTION. This is the single biggest caveat. You cannot confidently fork, patch, or redistribute the code inside a commercial product until it's clarified. If the field matters, ask the maintainer in writing, or treat any usage as internal-only and non-redistributed.
  • Zero stars, zero dependents means zero production signal. There is no evidence anyone has run this against your Nova major. Budget a branch spike against production-equivalent Nova before wiring it into a real resource — a clean composer require does not prove the Vue component compiles or renders.
  • XSS is structural, not incidental. "HTML field" is a euphemism for "raw markup stored in the admin." Even for trusted internal staff, enforce server-side sanitization with an allowlist, and store sanitized HTML, not raw. The admin panel is the highest-privilege surface in the app.
  • No database column means you must control visibility. A non-persistent field still participates in Nova's field lifecycle. If you don't call ->onlyOnForms(), ->onlyOnDetail(), ->hideFromIndex(), or ->hideFromDetail(), you'll see the block where you didn't expect it — often on the index view where it bloats every row.
  • Closures run per-row on index. If a closure field renders on the index, it fires per row. On a large table that's N+1-shaped pain. Restrict closure-based HTML to detail/form contexts.
  • Nova upgrade breakage is silent. Custom-field Vue components fail quietly on Nova majors — the resource loads but the field renders blank. When Nova upgrades, smoke-test every resource that uses this field, and pin the fork to your Nova matrix rather than floating on a branch.
  • Verify method names against source. Documentation is thin; the exact chainable methods for escaping (->escape(...)? ->asHtml()?), view vs closure vs string, and the class namespace need to be confirmed by reading src/ and resources/js/. Don't trust guesses in this assessment.
  • Vendor or fork it. With no maintainer signal, clone the source into your org's VCS early. If the repo disappears, your fork is the only copy — and pinning Composer to a VCS repo path makes the dependency stable without a Packagist release.
  • Keep the column generic. If you do persist HTML, use nullable longText. That way, replacing this field with a first-party one or a maintained WYSIWYG later is a code change, not a migration.
  • First-party replacement is days, not weeks. Nova's custom-field scaffolding is well documented. If any of the above is disqualifying, writing a scoped, sanitized, tested Html field in-house is a one-to-three-day job — worth pricing against the cost of owning an unmaintained component through the next Nova upgrade.
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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle