Skip to content

Upgrade Guide โ€‹

Upgrade PowerGrid from version 6 to version 7. If your tables only use datasource(), fields(), columns(), filters(), and setUp(), most of the work is dependencies and assets. Custom themes, published views, filter tests, and HTML fields need more attention.

Version Requirements โ€‹

Requirementv6v7
PHP8.2+8.3+
Laravel10+12+ (13 is supported)
Livewire3.5.4+4.0+
Tailwind CSSv3 or v4v4

TIP

PowerGrid 6.11 already runs on Livewire 4. Upgrade Livewire first, confirm everything works, then move to PowerGrid 7.

Installation โ€‹

bash
composer require power-components/livewire-powergrid:^7.0

Composer also installs power-components/turbine and power-components/partials. For XLSX or CSV, require OpenSpout 5 (the v4 driver is gone):

bash
composer require openspout/openspout:^5.0

Then compare your config with the new one (--force overwrites the file; commit first):

bash
php artisan vendor:publish --tag=livewire-powergrid-config --force

Summary of Changes โ€‹

Removed โ€‹

FeatureWhat to do instead
Bootstrap 5 theme, Themes\BaseTailwind, DaisyUI, or Flux. Or a child theme with Bootstrap classes
pg-primary-*accent-* from tailwind4.css. pg-secondary-* is unchanged
PowerGrid::lazy() (load more)Pagination. Livewire #[Lazy] is unrelated and still works
Laravel Pulse integrationNone
theme_style()theme()
isBootstrap5() / isTailwind()app('powergrid.theme') instanceof Tailwind (or DaisyUI / Flux)
window.pgActions / window.pgActionsHeaderServer-side Blade actions
WithExport traitRemove it. PowerGrid::exportable() is enough
OpenSpout 4 (openspout_v4)OpenSpout 5 (openspout_v5)
Built-in batch-export progress UI->progressView('your.view')
withSum(), withCount(), withAvg(), withMin(), withMax()summarize() / withSummary()
filter_attributes / FilterAttributesfilter_wire config or filterWire()
View namespace components.frameworks.*components.themes.* and components.structure.*
Nested Livewire powergrid-detailDetail rows render inline. PowerGrid::detail()->view() is unchanged
Pre-built dist/ JS/CSS, Tailwind 3Import resources/js/powergrid.js (or powergrid-flux.js) and Tailwind 4
Bundled TomSelectInstall TomSelect or SlimSelect and expose it on window

Changed โ€‹

AreaWhat changed
Custom themesstruct() only sets baseView. Tokens live in section methods
Theme config'tailwind', 'daisyui', or 'flux', or an FQCN. Register names with PowerGridManager::registerTheme()
Filter placementinline, dropdown, flyout, or null. outside is gone
Filter state$filters is keyed by field: ['type', 'value', 'op'?]
Dynamic filtersThe value no longer filters the query on its own
Field HTMLClosure strings are escaped. Return HtmlString, or set escape_closure_fields to false
Plugin update hooksPlugins call onPluginUpdated() only
Rows per pageCapped by max_per_page (1000), including "All" (0)
Editable / Toggleable viewsEditable view under powergrid-plugins. The Toggleable switch has no view
Per-table themetemplate(): ?Theme. customThemeClass() still works

JavaScript Import Path โ€‹

๐ŸŸฅ Likelihood Of Impact: High

The pre-built dist/powergrid bundle is gone. Import the package source:

javascriptresources/js/app.js
import './../../vendor/power-components/livewire-powergrid/dist/powergrid'
import './../../vendor/power-components/livewire-powergrid/resources/js/powergrid.js'

On Flux, import powergrid-flux.js instead (Flux uses <flux:dropdown> / <flux:menu>). Rebuild afterwards.

javascriptresources/js/app.js
import './../../vendor/power-components/livewire-powergrid/resources/js/powergrid-flux.js'

CSS and Tailwind 4 โ€‹

๐ŸŸฅ Likelihood Of Impact: High

PowerGrid 7 requires Tailwind 4 and no longer ships compiled CSS. If you already import resources/css/tailwind4.css, keep it. From Tailwind 3 / dist/tailwind.css: add @tailwindcss/vite, drop a Tailwind-only postcss.config.js, and remove presets that pointed at vendor/**/tailwind.config.js.

Tailwind theme โ€” tailwind4.css also @sources the package (files under app/ are picked up automatically):

cssresources/css/app.css
@import "tailwindcss";
@import "../../vendor/power-components/livewire-powergrid/resources/css/tailwind4.css";

DaisyUI or Flux โ€” do not import tailwind4.css. Use Configure PowerGrid and @source the package (vendor/ is gitignored):

cssresources/css/app.css
@source "../../vendor/power-components/livewire-powergrid/src/**/*.php";
@source "../../vendor/power-components/livewire-powergrid/resources/views/**/*.php";

pg-primary-* is gone. The Tailwind theme uses accent-* (green by default). Redefine --color-accent-* in @theme, and replace pg-primary-* classes in your own views. --color-pg-secondary-* (blue) is still defined in tailwind4.css.

Bootstrap 5 Removed โ€‹

๐ŸŸฅ Likelihood Of Impact: High

phpconfig/livewire-powergrid.php
'theme' => \PowerComponents\LivewirePowerGrid\Themes\Bootstrap5::class, 
'theme' => 'tailwind', 

Remove dist/bootstrap5.css. Themes\Base is gone. To keep Bootstrap classes, write a custom theme with $parentTheme = Tailwind::class. Markup is still the Tailwind markup.

Custom Themes โ€‹

๐ŸŸฅ Likelihood Of Impact: High

v6 returned a flat array per group (table(), checkbox(), searchBox(), โ€ฆ). v7: struct() only sets baseView; each group is a section method returning ['<group>' => [...]]. checkbox/radio live in table(), the search box in header(), all filter types in filter(). Set $parentTheme = Tailwind::class and override only what you change. Drop public string $name โ€” Theme::name() uses the class name.

php
class MyTheme extends Tailwind
{
    public function table(): array {}
    public function footer(): array {}
    public function checkbox(): array {}
    public function searchBox(): array {}
}
php
use PowerComponents\LivewirePowerGrid\Themes\Components;
use PowerComponents\LivewirePowerGrid\Themes\Tailwind;
use PowerComponents\LivewirePowerGrid\Themes\Theme;

class MyTheme extends Theme
{
    protected ?string $parentTheme = Tailwind::class;

    protected function baseView(): string
    {
        return 'livewire-powergrid::components.themes.tailwind';
    }

    public function struct(): Components\ThemeBuilder
    {
        return Components\ThemeBuilder::make($this->name())
            ->baseView($this->baseView());
    }

    public function table(): array
    {
        return $this->section('table', fn (Components\Table $table) => $table
            ->layout(fn (Components\Layout $layout) => $layout
                ->th('font-semibold px-3 py-3 text-left text-xs')
                ->td('px-3 py-2 whitespace-nowrap')
            )
        );
    }
}

Section methods: layout(), header(), table(), footer(), cols(), tabs(), filter(), editable(), toggleable(). DaisyUI ships no Blade files. Flux ships <flux:*> Blade only where the HTML differs.

Builder methods are camelCase (->thActions()); stored keys are snake_case (th_actions). Use snake_case in theme(), merge(), theme_overrides, and array sections โ€” a camelCase array key is ignored. See Custom Theme.

Where v6 keys went โ€‹

v6v7 token
table.header.theadtable.layout.thead
table.header.trtable.layout.thead_tr
table.header.thtable.layout.th
table.header.thActiontable.layout.th_actions
table.body.tbodytable.layout.tbody
table.body.trtable.layout.tr
table.body.tdtable.layout.td
table.body.tdActionsContainertable.body.td.actions_wrapper
table.body.tdEmptytable.layout.empty_state
table.body.trFilters / tdFilterstable.body.tr.filters / table.body.td.filters
table.layout.actionsheader.layout.actions
checkbox.* / radio.*table.checkbox.* / table.radio.*
searchBox.input / iconSearch / iconCloseheader.search_box.input / icon_search / icon_close
footer.footerfooter.layout.container
footer.selectfooter.layout.select
footer.footer_with_paginationfooter.pagination (view, not a class token)
filterInputText.*, filterBoolean.*, โ€ฆfilter.input_text.*, filter.boolean.*, โ€ฆ

table.body.td.actions_wrapper has no builder method. Set it in an array section, merge(), or theme_overrides.

Keys with no v7 equivalent โ€‹

Delete these:

  • table.layout.base, table.layout.div
  • table.body.tbodyEmpty, tdSummarize, trSummarize
  • editable.view โ€” the plugin renders powergrid-plugins::Editable.index
  • toggleable.view โ€” style the switch with color_on, color_off, color_on_dark, color_off_dark, knob_on
  • filter.multi_select.view โ€” markup is always <x-livewire-powergrid::inputs.select>

Theme Binding โ€‹

๐ŸŸฉ Likelihood Of Impact: Low

phpapp/Livewire/ProductTable.php
use App\PowerGridThemes\MyTheme;
use PowerComponents\LivewirePowerGrid\Themes\Theme;

public function customThemeClass(): ?string
{
    return MyTheme::class;
}
public function template(): ?Theme
{
    return new MyTheme();
}

customThemeClass() still works; template() wins when both are set. To change a few tokens without a class:

phpapp/Livewire/ProductTable.php
use PowerComponents\LivewirePowerGrid\Themes\Tailwind;
use PowerComponents\LivewirePowerGrid\Themes\Theme;

public function template(): ?Theme
{
    return Tailwind::make()->merge([
        'table' => [
            'layout' => [
                'tr' => 'border-b hover:bg-yellow-50',
            ],
        ],
    ]);
}

To select a custom theme by name: PowerGridManager::registerTheme('brand', BrandTheme::class) then 'theme' => 'brand'. Built-in names are in PowerGridManager::DEFAULT_THEMES (tailwind, daisyui, flux).

Helper Functions โ€‹

๐ŸŸฉ Likelihood Of Impact: Low

theme() reads the active theme by dot path; there is no $theme token array. theme_view('header') returns the resolved view name. isBootstrap5(), isTailwind(), and the once() polyfill are gone โ€” use Laravel's once().

blade
<td class="{{ theme_style($theme, 'table.body.td') }}">
@if($theme['name'] === 'tailwind')
blade
<td class="{{ theme('table.layout.td') }}">
@if(app('powergrid.theme') instanceof \PowerComponents\LivewirePowerGrid\Themes\Tailwind)

Theme::name() is the kebab-case class short name (tailwind, flux, daisy-u-i). Prefer instanceof.

Published Views โ€‹

๐ŸŸง Likelihood Of Impact: Medium

v6v7
resources/views/vendor/livewire-powergrid/components/frameworks/tailwind/resources/views/vendor/livewire-powergrid/components/themes/tailwind/

Shared layout lives in components/structure/. A theme ships Blade only when the HTML differs. DaisyUI ships none.

bash
php artisan vendor:publish --tag=livewire-powergrid-views

DANGER

Published views are a frozen copy. Prefer theme tokens.

If you keep them: republish from v7 (do not move v6 files), remove Bootstrap conditionals, replace theme_style() with theme(), stop using a $theme token array, and delete published livewire/detail.blade.php.

Filter Placement โ€‹

๐ŸŸง Likelihood Of Impact: Medium

outside is no longer valid. Filters just stop showing. Dropdown and flyout write to draftFilters and commit on applyFilters().

phpconfig/livewire-powergrid.php
'filter' => 'outside', 
'filter' => 'inline', 
ValueBehavior
inlineInside the table. Filters as you type.
dropdownPopover on a Filter button. Applied on "Apply".
flyoutSide drawer. Applied on "Apply".
nullNo filter UI.
phpconfig/livewire-powergrid.php
'filter_flyout' => [
    'position' => 'right', // 'left' or 'right'
    'close_on_escape' => true,
    'close_on_click_outside' => true,
],

Per table:

phpapp/Livewire/ProductTable.php
public function boot(): void
{
    config(['livewire-powergrid.filter' => 'flyout']);

    parent::boot();
}

Filter State โ€‹

๐ŸŸฅ Likelihood Of Impact: High

v6 grouped $filters by type (filters.input_text.name). v7 groups by field. Old paths do not throw โ€” they just stop filtering.

php
$this->filters['name'] = [
    'type' => 'input_text',
    'value' => 'pizza',
    'op' => 'contains',
];

Tests โ€‹

phptests/Feature/ProductTableTest.php
Livewire::test(ProductTable::class)
    ->set('filters.input_text.name', 'pizza') 
    ->set('filters.name.value', 'pizza') 
    ->assertSee('Pizza');
Filterv6 pathv7 path
Text valuefilters.input_text.namefilters.name.value
Text operatorfilters.input_text_options.namefilters.name.op
Number rangefilters.number.price.startfilters.price.value.start / .value.end
Booleanfilters.boolean.in_stockfilters.in_stock.value
Selectfilters.select.category_idfilters.category_id.value

Table updates now send partial HTML, so Livewire::test() assertions see stale rows. Add <env name="POWERGRID_PARTIALS_ENABLED" value="false"/> to phpunit.xml. See Testing Tables.

Dropdown and flyout: set the draft, then apply:

phptests/Feature/ProductTableTest.php
Livewire::test(ProductTable::class)
    ->set('draftFilters.name.value', 'pizza')
    ->call('applyFilters')
    ->assertSee('Pizza');

Dynamic filters โ€‹

A Filter::dynamic() bound to a built-in path such as filters.select.in_stock no longer runs as that filter type. The value lands in filters.in_stock.value with type dynamic. Apply it yourself:

phpapp/Livewire/ProductTable.php
public function datasource(): Builder
{
    $inStock = data_get($this->filters, 'in_stock.value');

    return Product::query()
        ->when(filled($inStock), fn ($query) => $query->where('in_stock', $inStock));
}

public function filters(): array
{
    return [
        Filter::dynamic('in_stock', 'in_stock')
            ->component('select')
            ->attributes([
                'wire:model.live' => 'filters.in_stock.value', 
                // ...
            ]),
    ];
}

Hooks and methods โ€‹

v6v7
afterChangedInputTextFilter(), afterChangedSelectFilter(), and the other afterChanged*Filter() hooksafterFilterChanged(string $field, array $record)
filterInputText(), filterInputTextOptions(), filterSelect(), filterBoolean(), filterNumberStart(), filterNumberEnd()putFilterRecord() then commitFilters()

multiSelectChanged() stays.

Filter bindings โ€‹

filter_attributes and the FilterAttributes classes are gone. Set modifiers in filter_wire, or return the same array from filterWire() (slots: value, operator, start, end, formatted):

phpconfig/livewire-powergrid.php
'filter_wire' => [
    'input_text' => ['value' => 'live.debounce.800ms'],
],

Saved state โ€‹

Persist still uses cookies (default), session, or cache. v7 restores the payload and canonicalizes $filters into field records that must include type. v6 filters were keyed by type, so those saved filters are not applied. Sorting and column visibility still restore when the payload uses the same keys.

Lazy Loading โ€‹

๐ŸŸง Likelihood Of Impact: Medium

PowerGrid::lazy(), LazyManager, loadMore(), hasLazyEnabled(), getLazyKeys(), and canLoadMore() are gone. Livewire's #[Lazy] is unrelated and still works.

phpapp/Livewire/ProductTable.php
public function setUp(): array
{
    return [
        PowerGrid::lazy() 
            ->rowsPerChildren(25), 
        PowerGrid::footer() 
            ->showPerPage(25, [10, 25, 50, 100]), 
    ];
}

A page also loads at most max_per_page rows (default 1000), including the "All" option (0) in showPerPage(). Set the config to 0 to remove the cap.

Export Setup โ€‹

๐ŸŸฅ Likelihood Of Impact: High

Remove WithExport. PowerGrid::exportable() in setUp() is enough.

phpapp/Livewire/ProductTable.php
use PowerComponents\LivewirePowerGrid\Traits\WithExport; 
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
use PowerComponents\LivewirePowerGrid\Facades\PowerGrid;

class ProductTable extends PowerGridComponent
{
    use WithExport; 

    public function setUp(): array
    {
        return [
            PowerGrid::exportable('my-export-file')
                ->type(Exportable::TYPE_XLS, Exportable::TYPE_CSV),
        ];
    }
}

Export classes moved to Plugins. Only OpenSpout 5 remains. v6 defaulted to openspout_v4:

phpconfig/livewire-powergrid.php
use PowerComponents\LivewirePowerGrid\Components\Exports\OpenSpout\v5\{ExportToCsv, ExportToXLS}; 
use PowerComponents\LivewirePowerGrid\Plugins\Export\OpenSpout\v5\{ExportToCsv, ExportToXLS}; 

'exportable' => [
    'default' => 'openspout_v4', 
    'default' => 'openspout_v5', 
    'openspout_v5' => [
        'xlsx' => ExportToXLS::class,
        'csv' => ExportToCsv::class,
    ],
    'openspout_v4' => [...], 
],

Queued (batch) exports show no progress bar unless you pass ->progressView('your.view'). The view receives $exportState and $tableName. See Exporting Data.

Field HTML Requires HtmlString โ€‹

๐ŸŸฅ Likelihood Of Impact: High

v7 escapes plain string field values with e(). HTML that used to render now shows as text. Escape user data inside the HtmlString yourself. Search fields() for return '< and Blade::render(. To keep v6 behavior while you migrate, set 'escape_closure_fields' => false. See HTML shows up as text in a cell.

phpapp/Livewire/ProductTable.php
use Illuminate\Support\HtmlString;

->add('status_badge', fn ($product): string => $this->statusBadge($product->in_stock)); 
->add('status_badge', fn ($product): HtmlString => new HtmlString( 
    '<span class="badge">'.e($product->in_stock ? 'Yes' : 'No').'</span>'
));

Column Summaries โ€‹

๐ŸŸง Likelihood Of Impact: Medium

phpapp/Livewire/ProductTable.php
Column::make('Price', 'price')
    ->withSum('Sum Price', header: true, footer: false) 
    ->summarize('sum', 'Sum Price', header: true, footer: false) 

summarize() accepts sum, count, avg, min, and max. For a custom calculation, use withSummary($key, $label, Closure $using).

Plugin Update Hooks โ€‹

๐ŸŸฅ Likelihood Of Impact: High

Editable and Toggleable call only onPluginUpdated(). onUpdatedEditable() and onUpdatedToggleable() are deprecated and never called, so overriding them does nothing.

phpapp/Livewire/ProductTable.php
public function onUpdatedEditable(string|int $id, string $field, string $value): void
{
    Product::query()->find($id)->update([
        $field => $value,
    ]);
}
public function onPluginUpdated(string $plugin, string $event, array $params): void
{
    if (in_array($plugin, ['editable', 'toggleable']) && $event === 'updated') {
        Product::query()->find($params['id'])->update([
            $params['field'] => $params['value'],
        ]);
    }
}

$params contains id, field, and value. Built-in plugins live in PowerGridManager::DEFAULT_PLUGINS; plugins() merges extras and never drops the defaults.

Server-Side Actions โ€‹

๐ŸŸฉ Likelihood Of Impact: Low

Actions render as Blade on the server. window.pgActions / window.pgActionsHeader are gone. Switch custom JS to Livewire events, or use Button and actionRules():

phpapp/Livewire/ProductTable.php
public function actions($row): array
{
    return [
        Button::add('edit')
            ->slot('Edit')
            ->class('text-indigo-600')
            ->dispatch('edit', ['rowId' => $row->id]),
    ];
}

Editable and Toggleable Views โ€‹

๐ŸŸฉ Likelihood Of Impact: Low

To override the editable cell, place resources/views/vendor/powergrid-plugins/Editable/index.blade.php (it replaces v6 components/frameworks/tailwind/editable.blade.php). It is not in the livewire-powergrid-views tag.

The toggleable switch is built in PHP, so there is no view to override. Style it with the toggleable tokens (color_on, color_off, color_on_dark, color_off_dark, knob_on). See Plugins.

Multi-Select Libraries โ€‹

๐ŸŸง Likelihood Of Impact: Medium

PowerGrid does not bundle TomSelect and does not inject TomSelect or SlimSelect from a CDN. Install the library and expose it on window:

bash
npm install tom-select
javascriptresources/js/app.js
import TomSelect from 'tom-select'
window.TomSelect = TomSelect

For SlimSelect: npm install slim-select and window.SlimSelect = SlimSelect. If the library is missing, the filter does not load and the console says what to install.

plugins.select.default still chooses tom or slim. The default is now slim โ€” set it back to tom if you republish the config and use TomSelect.

Other Changes โ€‹

๐ŸŸฉ Likelihood Of Impact: Low

  • Pulse: remove public bool $measurePerformance = true;, PowerGridPerformanceRecorder::class from config/pulse.php, POWERGRID_RECORD_ENABLED, and <livewire:powergrid-performance-card />.
  • Detail rows: powergrid-detail is gone. Rows render in the table body. Remove <livewire:powergrid-detail> and published livewire/detail.blade.php. PowerGrid::detail()->view() is unchanged.
  • Empty state: noDataLabel() still works but is deprecated. Override renderEmptyState().
  • Row templates: rowTemplates() and Column::template() stay. They render on the server with escaped values. pg-render-row-template.js and window.pgRowTemplates_* are gone.
  • Icons: icon_resources is gone, so v6 aliases such as ->icon('default-trash') no longer resolve. Pass a Blade component name instead: ->icon('svg.trash') for resources/views/components/svg/trash.blade.php.
  • Internal row keys: __powergrid_rules, __powergrid_loop, and __powergrid_actions were renamed to __turbine_*.

Configuration File โ€‹

Removed keys โ€‹

phpconfig/livewire-powergrid.php
'icon_resources' => [...], 
'filter_attributes' => [...], 
'exportable' => [
    'openspout_v4' => [...], 
],

New keys โ€‹

phpconfig/livewire-powergrid.php
'theme_overrides' => [
    // 'table' => ['layout' => ['th' => 'font-bold px-4 py-3']],
],

'filter_flyout' => [
    'position' => 'right',
    'close_on_escape' => true,
    'close_on_click_outside' => true,
],

'filter_wire' => [
    // 'input_text' => ['value' => 'live.debounce.800ms'],
],

'max_per_page' => 1000,

Changed keys โ€‹

  • theme accepts 'tailwind', 'daisyui', 'flux', or an FQCN.
  • plugins.select.default is 'slim'.
  • exportable points at Plugins\Export\OpenSpout\v5.

Public API โ€‹

datasource(), fields(), columns(), filters(), setUp(), Column, Button, and the PowerGrid, Filter, and Rule facades work as before. Classes that moved into power-components/turbine still resolve under PowerComponents\LivewirePowerGrid\.... See Portable Grid Definitions if the same grid also feeds Inertia or a REST endpoint.

Pre-Migration Checklist โ€‹

bash
grep -rn "theme_style\|isBootstrap5\|isTailwind" app/ resources/
grep -rn "PowerGrid::lazy\|LazyManager\|loadMore" app/
grep -rn "window.pgActions" resources/
grep -rn "WithExport\|measurePerformance" app/
grep -rn "Themes\\\\Bootstrap5\|Themes\\\\Base" app/ config/
grep -rn "powergrid-detail" app/ resources/
grep -rn "livewire-powergrid/dist" resources/
grep -rn "Components\\\\Exports\\\\OpenSpout\|filter_attributes" app/ config/
grep -rn "'filter' => 'outside'" app/ config/
grep -rn "withSum\|withCount\|withAvg\|withMin\|withMax" app/
grep -rn "onUpdatedEditable\|onUpdatedToggleable\|afterChanged" app/
grep -rn "Filter::dynamic" app/
grep -rn "filters\.\(input_text\|select\|number\|boolean\|multi_select\|datetime\|date\)" app/ tests/ resources/
grep -rn "pg-primary" app/ resources/
find resources/views/vendor/livewire-powergrid/components/frameworks -type f
  • [ ] Custom themes rewritten with section methods and snake_case keys
  • [ ] Published views republished from v7, nothing left in frameworks/
  • [ ] PowerGrid::lazy() removed
  • [ ] WithExport removed, export classes point to Plugins\Export\OpenSpout\v5
  • [ ] HTML in fields() wrapped in HtmlString (or escape_closure_fields set to false)
  • [ ] withSum() and friends replaced with summarize()
  • [ ] onUpdatedEditable() / onUpdatedToggleable() moved to onPluginUpdated()
  • [ ] Filter paths updated in tests, and dynamic filters applied in code
  • [ ] JS and CSS import from resources/js and resources/css
  • [ ] filter config is inline, dropdown, flyout, or null
  • [ ] Pulse integration removed

Step-by-Step Order โ€‹

  1. Upgrade PHP, Laravel, Livewire, and Tailwind to the versions above
  2. Run composer require power-components/livewire-powergrid:^7.0
  3. Merge the new config keys
  4. Update the Vite entry (powergrid.js or powergrid-flux.js) and the CSS, then rebuild
  5. Rewrite custom themes
  6. Republish views if you need them, and replace the old helpers
  7. Remove lazy loading
  8. Remove WithExport and update export classes
  9. Wrap HTML fields in HtmlString, or set escape_closure_fields to false
  10. Replace summaries and plugin update hooks
  11. Fix filter placement, filter paths, dynamic filters, and tests
  12. Open every table and try sorting, filtering, pagination, export, editing, and toggles

Troubleshooting โ€‹

Target class [...\Themes\Bootstrap5] does not exist โ€‹

Set 'theme' => 'tailwind' (or daisyui / flux) in config/livewire-powergrid.php.

Unable to find component: [powergrid-detail] โ€‹

Remove <livewire:powergrid-detail> and any published livewire/detail.blade.php.

Call to undefined function theme_style() โ€‹

Use theme('table.layout.td'): a dot path, no $theme argument.

Call to undefined method ...PowerGridManager::lazy() โ€‹

Remove it and use PowerGrid::footer()->showPerPage().

Method ...Column::withSum does not exist โ€‹

Use ->summarize('sum', 'Label').

View [components.frameworks.tailwind.header] not found โ€‹

The namespace is now components.themes.

HTML shows up as text in a cell โ€‹

The cell shows markup like <span class="badge">Yes</span> instead of a badge. v7 escapes strings returned by fields() closures.

Return an HtmlString from the closure:

phpapp/Livewire/ProductTable.php
use Illuminate\Support\HtmlString;

->add('status_badge', fn ($product): string => Blade::render( 
->add('status_badge', fn ($product): HtmlString => new HtmlString(Blade::render( 
    '<span class="badge">{{ $label }}</span>',
    ['label' => $product->in_stock ? 'Yes' : 'No'],
)); 
))); 

Or keep v6 behavior for every table while you migrate. Closure strings then render as raw HTML, so escape user data with e() yourself:

phpconfig/livewire-powergrid.php
'escape_closure_fields' => false,

Inline edits or toggles don't save โ€‹

Move your code from onUpdatedEditable() / onUpdatedToggleable() to onPluginUpdated().

Filters don't apply โ€‹

Use the new paths, for example filters.name.value. For dropdown and flyout, set draftFilters.* and call applyFilters(). Dynamic filters must be applied in your own code.

A theme token has no effect โ€‹

Use the snake_case key (th_actions, not thActions) in arrays, merge(), and theme_overrides.

pgFlatpickr, pgExport, or pgTomSelect is not defined โ€‹

Import resources/js/powergrid.js (or powergrid-flux.js) and rebuild. Also install and expose any third-party library you use: flatpickr, TomSelect, or SlimSelect.

Styles are missing after the upgrade โ€‹

On Tailwind, import tailwind4.css. On DaisyUI or Flux, add the @source lines for the package from CSS and Tailwind 4. Tailwind skips vendor/ otherwise.

Created By Luan Freitas and @DanSysAnalyst