# Create Powergrid Plugin

> Create a complete PowerGrid plugin from scratch, including PHP class, Column macro, Blade view, Alpine.js component, and registration.

- Skill: `power-components/create-powergrid-plugin` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add power-components/create-powergrid-plugin`
- Raw SKILL.md: https://api.skillmd.com/api/skills/power-components/create-powergrid-plugin/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: power-components (https://skillmd.com/u/power-components)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/power-components/create-powergrid-plugin

---


## 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:

1. `app/PowerGrid/Plugins/{PluginName}/{PluginName}Plugin.php` - Plugin class
2. `app/PowerGrid/Plugins/{PluginName}/index.blade.php` - Blade template
3. `app/PowerGrid/Plugins/{PluginName}/index.js` - Alpine.js component
4. `app/Providers/PowerGridPluginServiceProvider.php` - ServiceProvider

### Files to modify:

1. `bootstrap/providers.php` - Register the ServiceProvider
2. `app/Providers/AppServiceProvider.php` - Add plugin to `PowerGrid::plugins([...])`
3. User's PowerGrid component - Add column + hook method

## Critical Rules

1. **Create plugins in user's project**, never in the powergrid package
2. **ServiceProvider must call `boot()`** and register view namespace with `loadViewsFrom()`
3. **Alpine.js dispatch must use array format**: `[field, id, value]` (NOT object `{field, id, value}`)
4. **Render initial values server-side** with `@foreach`/`@selected()` - do NOT use `x-model` for initial state
5. **Model `$fillable` must include** the field being updated
6. **No proxy method needed** - `pgPluginListener` in Listeners.php handles routing generically
7. **Theme-aware markup uses tokens, not `instanceof`.** Contribute classes via `PluginBase::themeTokens()`; resolve views with `theme_view($alias)` and fall back to `powergrid-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:

```php
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.

```php
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

1. Gather requirements (plugin name, macro signature, interaction type, hook name)
2. Read `REFERENCE.md` in this skill directory for templates and full details
3. Create the plugin files following the templates
4. Register ServiceProvider and plugin
5. Add column + hook to user's component
6. Verify it works

For complete templates, architecture details, and troubleshooting, see:
`REFERENCE.md`

