What I do
Scaffold a complete external PowerGrid plugin in the user's project (NOT in the package).
When to use me
- A new interactive column behavior is needed (e.g., selectable, colorpicker, rating)
- The behavior requires its own Blade view and/or Alpine.js component
- The plugin needs to respond to user interactions via Livewire events
Quick Overview
Plugins are created in the user's project at app/PowerGrid/Plugins/{PluginName}/.
They do NOT require modifying the PowerGrid package.
Files to create:
app/PowerGrid/Plugins/{PluginName}/{PluginName}Plugin.php- Plugin classapp/PowerGrid/Plugins/{PluginName}/index.blade.php- Blade templateapp/PowerGrid/Plugins/{PluginName}/index.js- Alpine.js componentapp/Providers/PowerGridPluginServiceProvider.php- ServiceProvider
Files to modify:
bootstrap/providers.php- Register the ServiceProviderapp/Providers/AppServiceProvider.php- Add plugin toPowerGrid::plugins([...])- User's PowerGrid component - Add column + hook method
Critical Rules
- Create plugins in user's project, never in the powergrid package
- ServiceProvider must call
boot()and register view namespace withloadViewsFrom() - Alpine.js dispatch must use array format:
[field, id, value](NOT object{field, id, value}) - Render initial values server-side with
@foreach/@selected()- do NOT usex-modelfor initial state - Model
$fillablemust include the field being updated - No proxy method needed -
pgPluginListenerin Listeners.php handles routing generically - Theme-aware markup uses tokens, not
instanceof. Contribute classes viaPluginBase::themeTokens(); resolve views withtheme_view($alias)and fall back topowergrid-plugins::{PluginName}.themes.*.
Theme-aware plugins
Plugins can inject CSS-class tokens and ship theme-aware Blade without theme conditionals.
PluginBase::themeTokens() is merged into every theme in Theme::resolveTokens() (after the theme's own section methods, before config('livewire-powergrid.theme_overrides')). It is a raw array (not run through HasProperties::toArray()), so keys must already be snake_cased. The tabs group (list / tab / tab_active / tab_inactive / badge / badge_active / badge_inactive / optional view) is the first real example of a plugin-shaped token surface:
public static function themeTokens(): array
{
return [
'my_plugin' => [
'wrapper' => 'flex items-center gap-2',
'button' => 'rounded-md px-2 py-1 text-sm',
],
];
}
View resolution follows src/Plugins/FilterBuilder/FilterBuilderPlugin.php::resolveThemeView() (and HasTabs::tabsView()): try theme_view($alias), then fall back to a packaged powergrid-plugins:: view. Flux-style themes select a different blade by setting a *.view token (e.g. Flux tabs.view → powergrid-plugins::Tabs.themes.flux); do not branch on instanceof DaisyUI / instanceof Flux in new plugins.
private function resolveThemeView(): string
{
$tokenView = theme_view('header.my_plugin'); // or 'tabs', 'header.export', ...
if ($tokenView !== '' && view()->exists($tokenView)) {
return $tokenView;
}
$fallback = 'powergrid-plugins::{PluginName}.themes.index';
return view()->exists($fallback) ? $fallback : '';
}
Ship one shared token-driven blade (Tabs: resources/views/components/themes/tailwind/tabs.blade.php reads theme('tabs.*')) and only add a themes/flux.blade.php (etc.) when the HTML genuinely differs.
See REFERENCE.md for the full themeTokens() / resolveThemeView() templates.
Workflow
- Gather requirements (plugin name, macro signature, interaction type, hook name)
- Read
REFERENCE.mdin this skill directory for templates and full details - Create the plugin files following the templates
- Register ServiceProvider and plugin
- Add column + hook to user's component
- Verify it works
For complete templates, architecture details, and troubleshooting, see:
REFERENCE.md