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 Index Textarea Laravel Package

dillingham/nova-index-textarea

A Laravel Nova field that makes textarea columns searchable and indexable, so long-form content shows up in Nova search results and list cards instead of being ignored. A drop-in replacement for Nova's Textarea field.

View on GitHub
Deep Wiki
Context7

Getting Started

dillingham/nova-index-textarea exists to solve one narrow annoyance: Nova's stock Textarea field is hidden from the index view, so any long-form column (notes, bio, internal comments, JSON blobs) is invisible in the resource table until you click into a record. This package gives you a Textarea subclass that is index-visible and truncates the output to a sane cell width.

Install it like any Nova tool:

composer require dillingham/nova-index-textarea

There is nothing to publish — no config, no migrations, no service-provider registration. The entire package is one field class under vendor/dillingham/nova-index-textarea/src/. Read that file first. At 15 stars and a last release in February 2019, the README is thinner than the source, and the source is short enough to audit in two minutes. Confirm three things before you build on it:

  1. The exact class namespace (packages of this vintage are inconsistent about whether it's Dillingham\NovaIndexTextarea\... or Dillingham\IndexTextarea\...).
  2. The name of the limiting method (limit(), indexLimit(), chars(), etc.) and whether it takes characters or words.
  3. Whether it ships compiled JS or is pure PHP. If it has a dist/ folder with a Vue component built against Nova 1.x/2.x tooling, that is your compatibility risk; if it's PHP-only and just flips $showOnIndex, it will survive Nova upgrades far better.

Your first use case is almost always a support/triage table: a Ticket or Lead resource where agents need to skim the first ~100 characters of a description column without opening each record.

use Dillingham\NovaIndexTextarea\IndexTextarea; // verify namespace

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Subject'),
        IndexTextarea::make('Description', 'description')
            ->limit(120)
            ->sortable(),
    ];
}

If the truncation method doesn't exist or behaves unexpectedly, the field still works as a plain index-visible textarea — you just get browser-side overflow instead of clean ellipses, which you can fix with CSS or a displayUsing callback (see below).

Implementation Patterns

Two-field split for index vs. detail. The most robust pattern in any Nova codebase is to make the truncated version an index-only artifact and keep the real editor for forms and detail:

IndexTextarea::make('Description')
    ->onlyOnIndex()
    ->limit(100),

Textarea::make('Description')
    ->hideFromIndex()
    ->alwaysShow()          // full text on detail
    ->rules('required', 'max:5000'),

This keeps the truncation cosmetic and guarantees the editable field's value is never mutated by display logic. It also means you can swap the package out later without touching your forms.

Prefer displayUsing when you don't need the package at all. For most resources the same result is a one-liner on a normal Text field:

Text::make('Description')
    ->displayUsing(fn ($value) => Str::limit($value, 100))
    ->onlyOnIndex(),

Adopt the package only if you genuinely want the textarea component (multi-line styling, form behaviour) in the same field definition. Otherwise you're taking a dependency for something Str::limit already does — and displayUsing has the advantage of being supported by every Nova version.

Centralise limits. Hard-coded ->limit(120) scattered across twenty resources rots fast. Define the limit once, either in a small base resource class or a static helper:

// app/Nova/Concerns/HasIndexTextareas.php
protected function indexTextarea(string $name, int $limit = 100)
{
    return IndexTextarea::make($name)->limit($limit)->rules('nullable', 'string');
}

Then $this->indexTextarea('Notes') in each resource, and one config value to tune the whole admin.

Resolve values server-side when the column isn't the raw text. If the description is Markdown or HTML, strip it before truncating so the index cell doesn't show **bold** or  :

IndexTextarea::make('Description')
    ->resolveUsing(fn ($value) => Str::limit(strip_tags($value), 100))

Be aware this changes the value for every view of that field instance, including the detail page — which is why the two-field split above is usually the better shape.

Pair with indexQuery for search. Truncation is cosmetic; your users will still want to search the full column. If the field is ->searchable(), Nova does a LIKE %term% against the underlying column, which works fine on TEXT but will not use an index on MySQL. On large tables, restrict search to the first N characters or move the column to a generated/stored short column.

Gotchas and Tips

Compatibility is the headline risk. Last commit was early 2019 — that predates Nova 4 (Vue 3 + Vite) and any PHP 8.1+ type-safety work. If the package ships compiled Vue 2 field assets, assume they will not load cleanly in Nova 4/5 and test in a staging Nova instance before merging. If it is PHP-only and simply extends Laravel\Nova\Fields\Textarea, it will almost certainly keep working, because the Textarea class and the showOnIndex property are stable. Determine which case you're in on day one.

Audit the namespace before you write twenty imports. Composer's autoload block in vendor/dillingham/nova-index-textarea/composer.json is authoritative. Don't trust blog snippets — packages this small often get renamed between author and packagist.

Truncation is not the same as redaction. A truncated password_reset_token or api_secret column is still leaking the first 100 characters into the DOM and into any screenshot your support team takes. Never put this field on a resource that exposes sensitive columns; use Text::make(...)->displayUsing(fn () => '••••') or hideFromIndex() instead.

Newlines collapse in the index cell. A TEXT column with paragraphs renders as one long run-on line. Nova's table cells don't preserve whitespace by default. Either accept it, add ->displayUsing(fn ($v) => Str::limit(preg_replace('/\s+/', ' ', $v), 100)) to normalise whitespace, or add a small custom CSS rule (white-space: pre-line) in Nova::style().

Long unbroken tokens break the table layout. URLs, base64 strings, and hashes with no spaces will blow out the column width regardless of your character limit. Add break-words/overflow-wrap: anywhere via Nova::style(), or use Str::limit after inserting zero-width break opportunities.

Sorting on TEXT columns is slow and sometimes wrong. ->sortable() maps to ORDER BY description, which on MySQL TEXT is an unindexed filesort. It works on small tables and falls over on anything past ~100k rows. If sorting matters, sort by a derived title/summary column instead.

Don't select giant columns you don't need. Every index query pulls the full TEXT value even though you display 100 characters. On a table with 50 rows of 20KB descriptions that's a megabyte per page load. If this becomes a problem, use indexQuery to select a SUBSTRING(description, 1, 200) as description and let the field truncate the already-short string.

resolveUsing mutates the model attribute. Anything you do in resolveUsing/displayUsing on the same field instance affects detail and form views too. If you find yourself writing conditionals like $request->isMethod('GET') && $request->routeIs('nova.api.resources.index'), stop and switch to the two-field pattern instead.

Escape by default; be paranoid about asHtml. Nova escapes field output unless you explicitly opt into HTML. If you enable HTML rendering to preserve formatting, you've reintroduced XSS from user-submitted content and the truncation might slice a tag in half. Sanitise with a library, truncate after sanitising, and never truncate raw HTML on the byte boundary.

Migration escape hatch. Because the package is unmaintained, plan the exit. Replacing it takes five lines in a base resource:

protected function indexTextarea($name, $limit = 100)
{
    return Text::make($name)
        ->displayUsing(fn ($v) => Str::limit($v, $limit))
        ->onlyOnIndex();
}

Consider vendoring the package's single class into app/Nova/Fields/ instead of depending on packagist — you get the same behaviour, you own the maintenance, and you remove a stale dependency from your lockfile. For a package this small, that is usually the right call.

Test the truncation, not the layout. A simple Nova feature test asserting $response->assertSee(Str::limit($model->description, 100)) catches the common regression where someone upgrades Nova and the field silently stops showing on index.

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.
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
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource