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

Rapyd Livewire Laravel Package

zofe/rapyd-livewire

zofe/rapyd-livewire integrates Rapyd’s Laravel CRUD toolkit with Livewire, helping you build reactive admin panels, forms, and data tables from reusable components. Define fields and grids once, then get dynamic, AJAX-driven interfaces with less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish first, code second.

composer require zofe/rapyd-livewire
php artisan vendor:publish --provider="Zofe\RapydLivewire\RapydLivewireServiceProvider"

Publishing is not optional — the package ships its own config (config/rapyd-livewire.php), Blade views, and CSS/JS assets. If a table renders as unstyled HTML with raw <th> tags, you skipped this step or your Vite/Tailwind setup is overriding the published Bootstrap CSS.

Where to look first, in order:

  1. vendor/zofe/rapyd-livewire/src/Components/ — the base classes (DataTable, DataForm, DataGrid) are the API surface. Read them before the README; the docs are thin and the source is the real reference.
  2. vendor/zofe/rapyd-livewire/config/ — pagination size, view paths, asset paths, field-type registry.
  3. The README's demo app (or the package's own test suite) for a working end-to-end example.
  4. The parent zofe/rapyd-laravel docs — much of the widget vocabulary (fields, columns, rules()) is inherited, and the older docs fill the gaps the Livewire wrapper doesn't document.

Verify Livewire version compatibility before anything else. Check composer.json in the vendor directory. Livewire 2 and Livewire 3 differ on component hooks, event emitting ($emit vs $dispatch), and the mount()/boot() lifecycle. With 34 stars and a 0.29 score, assume the constraint may be older than your app.

First use case — a read-only DataTable. Pick a model you already have seeded. Create a dedicated Livewire component that extends the package's table class, point it at the model, add three columns, and mount it in a simple Blade view. Resist adding forms, custom buttons, or inline editing until the table paginates and searches correctly — that single step exercises config, views, assets, and Livewire wiring all at once, and it's where most setup failures surface.

use Zofe\RapydLivewire\Components\DataTable;

class UsersTable extends DataTable
{
    public function mount(): void
    {
        $this->model = \App\Models\User::class;
        $this->addColumn('text', ['name' => 'Name', 'sortable' => true]);
        $this->addColumn('text', ['name' => 'Email', 'sortable' => true]);
        $this->addColumn('text', ['name' => 'Created', 'sortable' => true]);
    }
}

Then <livewire:users-table /> in a view that already has @livewireStyles and @livewireScripts.

Implementation Patterns

Extend, don't configure from outside. The idiomatic pattern is one Livewire component per screen, extending the package's base class and configuring it in the appropriate lifecycle hook (mount() in most versions; check the base class for a build() or setup() hook). Keep the configuration declarative and close to the top of the method so the component reads like a spec.

DataTable — the workhorse. The patterns you'll reach for daily:

  • addColumn($type, ['name' => ..., 'sortable' => true]) for display columns.
  • addSearch('text', 'email') / addFilter('select', 'role') for the search bar — search fields are declared separately from columns, and forgetting this is why your table "doesn't search" on a column it clearly displays.
  • Default ordering and page size set once in the component, not in the view.
  • Row actions via closures that return URLs or emit events; mass actions for bulk delete/export always paired with a confirmation.
  • Scope the query in the component (where, with) rather than trusting the model's default; table performance is query performance.

DataForm — forms bound to a model. Fields are declared with a type and a name matching the database column or accessor, then chained with rules() for validation and modifiers for layout (placeholder, help text, default value). The save path is: declare fields → call the package's process/submit method in your save action → handle success and error callbacks. Keep your own $this->validate() out of it; the widget owns validation and will surface errors in its own markup. Redirect inside the success callback, not after the component method returns — Livewire will otherwise re-render the form with stale state.

DataGrid — inline editable tables. Use it when the edit interaction is genuinely tabular (bulk-editing prices, statuses, sort orders). For anything with more than ~6 fields or cross-field validation, a DataForm is less fighting and less fragile.

Compose table + form on one page. The most common real screen is a table with create/edit beside it. Two components, communicating via Livewire events:

// in the form's success callback
$this->dispatch('user-saved')->to(UsersTable::class);

and in the table, a listener that resets pagination and refreshes. This is cleaner than trying to make one component do both, and it keeps the form's validation state from leaking into the table's search state.

Custom cell rendering. For anything beyond plain text — status badges, avatar thumbnails, action dropdowns — use the column's closure/partial support rather than hacking the Blade template. Published views are a last resort: once you publish and edit rapyd's views, you own them across package upgrades. Prefer per-column overrides and keep a note of which views you've customized.

Authorization belongs in your component. Do the $this->authorize(...) or policy check in mount(), before any query runs. Don't rely on the widget to enforce visibility of row actions — hide the buttons yourself based on the same policy, or users will click buttons that 403.

Gotchas and Tips

Asset and CSS collisions are the #1 source of "it looks broken." The package assumes Bootstrap-era markup. Tailwind's preflight will strip list styles and table borders; a Vite pipeline that purges CSS will drop classes the package injects at runtime. If the table is functional but ugly, this is why — not a bug. Decide early whether you're isolating the table in a Bootstrap-styled layout or overriding the published views with your own markup.

Beware ambiguous column names on joins. Once you add a join() for a related name, sortable on a plain column name produces ORDER BY name and MySQL errors out. Qualify with the table name. Same for search columns.

Eager-load aggressively. The table renders every row on the page; a relationship accessor in a custom cell is an N+1 waiting to happen. Add with() in the component's query setup and check the query log on a 50-row page before shipping.

Validation is the widget's, not Livewire's. Don't mix $this->validate() with the widget's rules, and don't expect wire:model bindings on fields the widget renders. If validation messages aren't appearing, the rule string is usually wrong (Laravel pipe syntax) or the field name doesn't match the model attribute exactly.

Debugging checklist when a widget misbehaves, roughly in order of likelihood:

  1. Did you publish and re-publish after upgrading? Stale published views mask fixes.
  2. Is the model's $fillable/$guarded blocking the save silently?
  3. Is there a dd() in a success callback swallowing the redirect?
  4. Open the Livewire network payload — the component's public properties show exactly what the widget thinks the search/sort state is.
  5. Drop to the vendor source; with this package's adoption level, you will hit undocumented edges and the source is faster than searching.

Mass actions are dangerous by default. Bulk delete has no built-in undo. Put a confirmation modal in front of every destructive mass action, and verify the selected-IDs state survives a pagination change — a classic bug is selecting rows on page 1, paging, and acting on a stale set.

Pin the version in composer.json and snapshot the widget output in a feature test. With a small maintainer base, a minor bump can change rendered markup or a lifecycle hook. A single test that asserts "the users table shows 10 rows and searches by email" is cheap insurance and will catch a breaking upgrade before your users do.

Extension points worth knowing: the field-type registry in the config (register your own money or enum field once instead of repeating options everywhere), the ability to swap a component's view per-instance, and the base component classes themselves — subclassing to add a shared trait (e.g. a standard date-format column, or a scoped-tenant query) is the cheapest way to keep a dozen screens consistent.

Finally: budget for reading source. A package at this adoption level won't have a Stack Overflow answer for your problem. Weigh that against the speed of getting a CRUD screen standing up in an afternoon — that trade is the entire case for using it, and it's a real one, as long as you go in expecting to be the one who debugs it.

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