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

bbs-lab/nova-items-field

A Laravel Nova field for managing repeatable item lists inside your resources. Add, edit, reorder, and remove rows through a clean native Nova UI, with structured JSON storage that keeps multi-item data simple to build, validate, and maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements check first. This field targets Nova 5 and PHP ^8.4 with Laravel ^11 || ^12 || ^13. If your app is still on Nova 4 or PHP 8.3, you cannot adopt this release — treat it as a forward-looking option for new/upgraded projects only.

  1. Install:
    composer require bbs-lab/nova-items-field
    
  2. Add the JSON column and cast on the model (the field stores a list of scalars as JSON):
    $table->json('tags')->nullable();
    // Model
    protected $casts = ['tags' => 'array'];
    
  3. Attach the field to a Nova resource:
    use BBSLab\NovaItemsField\Items;
    
    Items::make('Tags')
        ->chips()
        ->suggestions(['laravel', 'nova', 'vue'])
        ->rules('max:10')
        ->itemRules('string', 'max:255');
    

Where to look first: the README's method list (chips, min/max, maxHeight, inputType, suggestions, addButtonPosition, hideAddButton, indexAsChips/indexAsList, detailsAsTotal, dependsOn, copy-to-clipboard) and the migration table if you're coming from blendbyte/nova-items-field.

First use case: a tags or bullet_points JSON column on an existing resource — drop the field in, enable ->chips() for tags or leave default numbered rows for ordered content like steps, and set ->itemRules('string', 'max:255') so bad rows surface inline instead of failing at save time.

Implementation Patterns

Pick the display mode by data semantics, not aesthetics.

  • ->chips() for unordered, short, dedupable values (tags, emails, labels).
  • Default structured rows (numbered, drag-to-reorder) for anything where order is meaningful — steps, bullet points, priority lists.

Use the right validation layer.

  • ->rules(...) = array-level rules (count/shape of the whole list).
  • ->itemRules(...) = per-element rules, rendered as inline per-row errors.
  • ->min() / ->max() = item-count constraints. Prefer these for counts over hand-written rules('max:10') — it keeps intent readable and avoids confusion with per-item max semantics.
Items::make('Steps')
    ->min(1)
    ->max(20)
    ->rules('required', 'array')
    ->itemRules('required', 'string', 'max:500');

Constrain suggestions if you need strictness. ->suggestions() is a datalist (autocomplete), not a whitelist. If only known values are allowed, pair it with ->itemRules('in:laravel,nova,vue').

Tune the editing surface for the content size.

  • ->maxHeight('320px') for long lists so the form doesn't sprawl.
  • ->inputType('email' | 'url' | ...) to get the right mobile keyboard/HTML semantics.
  • ->addButtonPosition(...) / ->hideAddButton() where the default add-button placement fights your form layout (e.g. fixed-length lists you seed elsewhere).
  • Custom button labels for non-English admin UIs; the package ships EN/FR and labels are publishable.

Use the tailored index/detail views deliberately.

  • Default index: count badge with hover tooltip — good for "how many tags?" at a glance.
  • ->indexAsChips() for short values you want visible in the table.
  • ->indexAsList() for a compact preview of ordered content.
  • ->detailsAsTotal() on detail pages when the individual values are noise and only the count matters.

Wire dependencies, not custom JS. dependsOn handles the common "show this field only when a mode/flag is selected" case; keep dependent state in plain Nova fields rather than reaching for custom field components.

Copy-to-clipboard is worth enabling on detail views for values users paste elsewhere (emails, IDs, tokens-as-strings), which removes a chunk of "select the text carefully" support tickets.

Treat ordering as data. Drag-and-drop (with keyboard support) implies array order is meaningful. Do not sort the array in an accessor/mutator or saving hook — you'll silently break the reordering UX and any downstream consumers relying on position.

Gotchas and Tips

  • JSON columns and querying. The value is a JSON array; where('tags', 'like', ...) is a trap. Use your DB's JSON operators (whereJsonContains on MySQL/Postgres/SQLite where supported) or, if you need heavy filtering, faceting, or sorting by tag, model it as a related table instead and keep this field for lightweight lists.
  • Index badge/count sorting isn't free. A count badge renders fine, but sorting or filtering the index by item count generally needs a computed column or custom index query — plan for it rather than assuming the field gives you sortable counts.
  • rules() vs itemRules() mix-ups are the most likely source of "why didn't my error show inline?" max:255 in rules() is not a per-item rule; put string-length constraints in itemRules().
  • Migration from blendbyte/nova-items-field: the namespace changes (BBSLab\NovaItemsField\Items). Follow the README migration table method-by-method; don't assume a rename-free swap, and re-check any published views/translations you had customized.
  • dependsOn + validation: hidden dependent fields still exist in the payload. If a field is conditionally hidden, make its rules conditional too (sometimes/required_if or ->rules() guarded by resolved state), otherwise validation can fire on values the user can't see.
  • Translations are publishable. If you support non-EN/FR locales, publish and translate the labels early; otherwise you get mixed-language forms.
  • Nova 5-only, PHP 8.4-only is the practical lock-in. Confirm your CI matrix and any shared internal packages match before installing, and pin the version in composer.json if you have multiple Nova apps on different tracks.
  • Test/quality signals are strong (100% PHP and JS coverage, MSI ≥ 80%, PHPStan level 8, Pint/ESLint), so edge cases around reorder/validation are less likely to bite — but still add a feature test that persists an array through the field and asserts the cast round-trips, since JSON encoding/empty-state handling is the usual integration failure point.
  • Empty vs null: decide once whether an empty list saves as [] or null and normalize on read; mixed states cause inconsistent min() behavior and confusing detail rendering.
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.
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics
robbiep/afterthedeadline
frankkessler/incontact-laravel-oauth2-rest
jlxh/laravel-userlog
davidmgilo/timetables
qylinfly/role-permission
reflect-digital/conduit
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr