# Plugins Overview

> Overview of all @toolbox-web/grid plugins — editing, selection, filtering, grouping, export, and more. Tree-shakeable, individually importable.

The `@toolbox-web/grid` plugin architecture allows you to extend the grid with powerful features while keeping the core bundle lightweight. Plugins are tree-shakeable — only import what you need.

:::tip[Features or Plugins? They do the same thing.]
**Features** and **plugins** are two APIs for enabling the same capabilities. The end result is identical — features are simply a simpler, declarative wrapper around plugins.

- **Features** (recommended) — Declare _what_ you want: `features: { selection: 'row' }`. Dependencies are auto-resolved, ordering is handled for you.
- **Plugins** (advanced) — Instantiate classes yourself: `plugins: [new SelectionPlugin({ mode: 'row' })]`. Useful when building custom plugins or extending `BaseGridPlugin`.

**If you're getting started, use features.** You can always switch to the plugin API later if you need more control — they're fully interchangeable.
:::

:::note[Angular: pair feature inputs with the per-feature directive]
The Angular tabs in plugin docs often show the shorthand `[selection]`, `[filtering]`, `[editing]`, etc. on `<tbw-grid>`. In **v1.4+** the recommended way to use those bindings is to import the matching per-feature directive (e.g. [`GridSelectionDirective`](/grid/angular/api/directives/gridselectiondirective.md) from `@toolbox-web/grid-angular/features/selection`) alongside `Grid` in the component's `imports`. The same bindings on the central `Grid` directive are still accepted for v1.x backward compatibility but are `@deprecated` and will be removed in v2.0. Apps that configure plugins through `[gridConfig]="{ features: { … } }"` are unaffected — see the [Angular getting-started guide](/grid/angular/getting-started.md#three-ways-to-configure-features) for the full breakdown.
:::

## Available Plugins

### Editing & Data Entry

| Plugin | Description |
| ------ | ----------- |
| [Editing](/grid/plugins/editing.md) | Inline cell editing with built-in editors |
| [Undo/Redo](/grid/plugins/undo-redo.md) | Undo/redo for cell edits with history stack |

:::note
Editing is opt-in. To enable `editable` and `editor` column properties, you must enable the editing feature (`features: { editing: true }`) or register the `EditingPlugin` directly. This keeps the core bundle lightweight and provides runtime validation to catch misconfigurations early.
:::

### Selection & Interaction

| Plugin | Description |
| ------ | ----------- |
| [Selection](/grid/plugins/selection.md) | Cell, row, and range selection with keyboard support |
| [Clipboard](/grid/plugins/clipboard.md) | Copy/paste with Ctrl+C/V |
| [Context Menu](/grid/plugins/context-menu.md) | Right-click context menus with submenus |
| [Reorder](/grid/plugins/reorder-columns.md) | Drag-and-drop column reordering |
| [Row Reorder](/grid/plugins/reorder-rows.md) | Drag-and-drop row reordering with keyboard support |

### Filtering & Sorting

| Plugin | Description |
| ------ | ----------- |
| [Filtering](/grid/plugins/filtering.md) | Column header filters with search and dropdown |
| [Multi-Sort](/grid/plugins/multi-sort.md) | Sort by multiple columns with priority indicators |

### Grouping & Hierarchy

| Plugin | Description |
| ------ | ----------- |
| [Row Grouping](/grid/plugins/grouping-rows.md) | Group rows by field values with expand/collapse |
| [Column Grouping](/grid/plugins/grouping-columns.md) | Visual column grouping with nested headers |
| [Tree](/grid/plugins/tree.md) | Hierarchical tree data display |
| [Master-Detail](/grid/plugins/master-detail.md) | Expandable detail rows |
| [Pivot](/grid/plugins/pivot.md) | Pivot table transformation with aggregations |

### Layout & Display

| Plugin | Description |
| ------ | ----------- |
| [Shell](/grid/plugins/shell.md) | Header bar (title + toolbar) and collapsible tool-panel sidebar |
| [Pinned Columns](/grid/plugins/pinned-columns.md) | Pin columns to left or right edge |
| [Pinned Rows](/grid/plugins/pinned-rows.md) | Status bar with aggregations and custom panels |
| [Visibility](/grid/plugins/visibility.md) | Show/hide columns dynamically |
| [Column Virtualization](/grid/plugins/column-virtualization.md) | Performance optimization for many columns |
| [Responsive](/grid/plugins/responsive.md) | Card layout for narrow containers and mobile |
| [Tooltip](/grid/plugins/tooltip.md) | Popover tooltips for truncated header and cell text |

### Data & Export

| Plugin | Description |
| ------ | ----------- |
| [Export](/grid/plugins/export.md) | Export to CSV, Excel (XML), and JSON formats |
| [Print](/grid/plugins/print.md) | Print-optimized layout with styling |
| [Server-Side](/grid/plugins/server-side.md) | Lazy loading from remote data sources |

## Plugin Dependencies

Some plugins depend on other plugins to function. Dependencies can be **hard** (required) or **soft** (optional enhancement).

### Dependency Types

| Type | Behavior | Example |
| ---- | -------- | ------- |
| **Hard (Required)** | Plugin will throw an error if the dependency is missing | UndoRedoPlugin → EditingPlugin |
| **Soft (Optional)** | Plugin works without it, but gains extra features when present | VisibilityPlugin → ReorderPlugin |

### Current Plugin Dependencies

| Plugin | Depends On | Type | Reason |
| ------ | ---------- | ---- | ------ |
| **UndoRedoPlugin** | EditingPlugin | Hard | Tracks cell edit history for undo/redo |
| **ClipboardPlugin** | SelectionPlugin | Soft | Enables copy/paste of selected cells instead of entire grid |
| **VisibilityPlugin** | ReorderPlugin | Soft | Enables drag-to-reorder columns in visibility panel |

### Plugin Load Order

When using the **features API** (recommended), dependencies are resolved automatically — you don't need to worry about ordering.

When using the **plugin API** directly, dependencies must be loaded **before** the dependent plugin:

```typescript
// ✅ Correct - EditingPlugin loaded before UndoRedoPlugin
plugins: [
  new EditingPlugin(),
  new UndoRedoPlugin(),
]

// ❌ Wrong - throws error at runtime
plugins: [
  new UndoRedoPlugin(), // Error: EditingPlugin required
  new EditingPlugin(),
]
```

For declaring dependencies in your own custom plugins, see [Custom Plugins → Plugin Dependencies](/grid/plugin-development/custom-plugins.md#plugin-dependencies).

## Using Features (Recommended)

The features API is the simplest and recommended way to enable grid capabilities. It provides:

- **Declarative configuration** — describe _what_ you want, not _how_ to wire it up
- **Automatic dependency resolution** — features auto-resolve plugin dependencies in the correct order
- **Tree-shaking** via side-effect imports — only the features you import are included in your bundle
- **Framework adapter integration** — React, Vue, and Angular adapters expose features as typed props

#### Vanilla

```typescript
// 1. Import features (side-effect imports for tree-shaking)
import '@toolbox-web/grid/features/selection';
import '@toolbox-web/grid/features/filtering';
import '@toolbox-web/grid/features/editing';

// 2. Configure declaratively
grid.gridConfig = {
  columns: [...],
  features: {
    selection: 'row',                       // shorthand
    filtering: { debounceMs: 300 },         // full config object
    editing: 'dblclick',                    // shorthand
  },
};
```

#### React

```tsx
import '@toolbox-web/grid-react/features/selection';
import '@toolbox-web/grid-react/features/filtering';
import '@toolbox-web/grid-react/features/editing';

<DataGrid
  rows={rows}
  columns={columns}
  selection="row"
  filtering={{ debounceMs: 300 }}
  editing="dblclick"
/>
```

#### Vue

```vue
<script setup>
import '@toolbox-web/grid-vue/features/selection';
import '@toolbox-web/grid-vue/features/filtering';
import '@toolbox-web/grid-vue/features/editing';
</script>

<DataGrid
  :rows="rows"
  :columns="columns"
  selection="row"
  :filtering="{ debounceMs: 300 }"
  editing="dblclick"
/>
```

#### Angular

```typescript
import { GridSelectionDirective } from '@toolbox-web/grid-angular/features/selection';
import { GridFilteringDirective } from '@toolbox-web/grid-angular/features/filtering';
import { GridEditingDirective } from '@toolbox-web/grid-angular/features/editing';
// In template:
// <tbw-grid [rows]="rows" [columns]="columns"
//   [selection]="'row'" [filtering]="{ debounceMs: 300 }" [editing]="'dblclick'" />
```

## Feature Reference (all features, side-effect import + accepted values)

One-line lookup for every feature. Import the side-effect once, then set the
matching `gridConfig.features.<name>` key (recommended) or the equivalent
framework prop. Paths below use the core package; adapters mirror them — replace
`@toolbox-web/grid` with `@toolbox-web/grid-react` / `-angular` / `-vue`.

| Feature key | Side-effect import | Accepted values |
|-------------|--------------------|-----------------|
| `selection` | `@toolbox-web/grid/features/selection` | `"cell"`, `"row"`, `"column"`, `"range"`, `["column", "row"]`, `{ mode: 'range', checkbox: true }` |
| `editing` | `…/features/editing` | `true`, `"click"`, `"dblclick"`, `"manual"`, `{ mode: 'row', editOn: 'click' }`, `{ mode: 'grid' }` (always-editable) |
| `multiSort` | `…/features/multi-sort` | `true`, `"single"`, `"multi"`, `{ maxSortColumns: 3 }` |
| `filtering` | `…/features/filtering` | `true`, `{ debounceMs: 200 }` |
| `clipboard` | `…/features/clipboard` | `true` (requires selection) |
| `undoRedo` | `…/features/undo-redo` | `true` (requires editing) |
| `contextMenu` | `…/features/context-menu` | `true`, `{ items: [...] }` |
| `reorderColumns` | `…/features/reorder-columns` | `true` |
| `reorderRows` | `…/features/reorder-rows` | `true` |
| `rowDragDrop` | `…/features/row-drag-drop` | `true`, `{ dropZone: 'employees' }` |
| `visibility` | `…/features/visibility` | `true` |
| `pinnedColumns` | `…/features/pinned-columns` | `true` |
| `pinnedRows` | `…/features/pinned-rows` | `true`, `{ slots: [{ position: 'bottom', aggregators: { … } }] }` |
| `groupingColumns` | `…/features/grouping-columns` | `true`, `{ columnGroups: [...] }` |
| `groupingRows` | `…/features/grouping-rows` | `{ groupOn: (row) => [row.department] }` |
| `tree` | `…/features/tree` | `{ childrenField: 'children' }` |
| `columnVirtualization` | `…/features/column-virtualization` | `true` |
| `masterDetail` | `…/features/master-detail` | `{ detailRenderer: (row, rowIndex) => '<div>…</div>' }` |
| `responsive` | `…/features/responsive` | `true`, `{ breakpoint: 768 }` |
| `export` | `…/features/export` | `true`, `{ fileName: 'data' }` |
| `print` | `…/features/print` | `true` |
| `pivot` | `…/features/pivot` | `{ rowGroupFields: ['region'], columnGroupFields: ['quarter'], valueFields: [{ field: 'revenue', aggFunc: 'sum' }] }` |
| `serverSide` | `…/features/server-side` | `{ dataSource: async (params) => … }` |
| `tooltip` | `…/features/tooltip` | `true`, `{ header: true, cell: false }` |
| `stickyRows` | `…/features/sticky-rows` | `{ isSticky: 'isSection' }`, `{ isSticky: (row) => row.isHeader, mode: 'stack', maxStacked: 3 }` |

Import every feature at once (prototyping only): `import '@toolbox-web/grid/features';`

### Import All Plugins

For rapid prototyping when bundle size is not critical:

```typescript
import { SelectionPlugin, FilteringPlugin, EditingPlugin } from '@toolbox-web/grid/all';
```

This imports the core grid and all 25 plugin modules. Use the `plugins` array to configure them:

```typescript
grid.gridConfig = {
  plugins: [
    new SelectionPlugin({ mode: 'row' }),
    new FilteringPlugin(),
    new EditingPlugin({ editOn: 'dblclick' }),
  ],
};
```

### Accessing Plugin Instances

Whether you use features or plugins, access runtime APIs the same way:

```typescript
const selection = grid.getPluginByName('selection');
if (selection) {
  selection.selectAll();
  selection.clearSelection();
  const ranges = selection.getSelectedRanges();
}
```

## Plugin Imperative API Reference (`grid.getPluginByName(name)`)

`grid.getPluginByName(name)` returns the live plugin instance (or `undefined` if
not loaded). The `name` is the plugin's registered key (NOT the class name).
Key imperative methods per plugin:

| Plugin | `name` key | Key imperative methods |
|--------|-----------|------------------------|
| SelectionPlugin | `selection` | `selectAll()`, `clearSelection()`, `getSelectedRanges()`, `getSelection()`, `selectRows(idx[])`, `getSelectedRowIndices()`, `getSelectedRows()`, `getSelectedColumns()` |
| EditingPlugin | `editing` | (dirtyTracking) `isDirty(rowId)`, `isPristine(rowId)`, `getDirtyRows()`, `markAsPristine(rowId)`, `markAllPristine()`, `markAsDirty(rowId)`, `revertRow(rowId)`, `getOriginalRow(rowId)` |
| FilteringPlugin | `filtering` | `setFilter()`, `setFilterModel()`, `clearAllFilters()`, `clearFieldFilter()` (all accept `{ silent: true }`), `getStaleFilters()`, `getBlankMode(field)`, `toggleBlankFilter(field, mode)` |
| MultiSortPlugin | `multiSort` | `getSortModel()`, `setSortModel(model)`, `clearSort()`, `getSortIndex(field)`, `getSortDirection(field)` |
| TreePlugin | `tree` | `expand(key)`, `collapse(key)`, `toggle(key)`, `expandAll()`, `collapseAll()`, `isExpanded(key)`, `getExpandedKeys()`, `expandToKey(key)`, `getFlattenedRows()`, `getRowByKey(key)` |
| GroupingRowsPlugin | `groupingRows` | `expand(key)`, `collapse(key)`, `toggle(key)`, `expandAll()`, `collapseAll()`, `isExpanded(key)`, `getExpandedGroups()`, `getGroupState()`, `getFlattenedRows()`, `setGroups(g)`, `getGroups()`, `setGroupRows(key, rows)`, `clearGroupRows(key?)` |
| GroupingColumnsPlugin | `groupingColumns` | `isGroupingActive()`, `getGroups()`, `getGroupColumns(groupId)`, `refresh()` |
| MasterDetailPlugin | `masterDetail` | `expand(rowIndex)`, `collapse(rowIndex)`, `toggle(rowIndex)`, `expandAll()`, `collapseAll()`, `isExpanded(rowIndex)`, `getExpandedRows()`, `getDetailElement(rowIndex)`, `getDetailData(rowIndex)`, `isDetailLoading(rowIndex)` |
| PivotPlugin | `pivot` | `enablePivot()`, `disablePivot()`, `isPivotActive()`, `getPivotResult()`, `setRowGroupFields(f)`, `setColumnGroupFields(f)`, `setValueFields(f)`, `refresh()`, `expandAll()`, `collapseAll()`, `getExpandedGroups()` |
| ClipboardPlugin | `clipboard` | `copy()`, `copy({ columns, rowIndices, includeHeaders })`, `copyRows(idx[], opts)`, `getSelectionAsText(opts)`, `paste()` |
| ExportPlugin | `export` | `exportCsv(opts)`, `exportExcel(opts)`, `exportJson(opts)`, `export()` (rows), `formatCsv(rows)`, `formatExcel(rows)`, `getResolvedColumns()` |
| VisibilityPlugin | `visibility` | `show()`, `hide()`, `toggle()`, `isPanelVisible()`, `isColumnVisible(field)`, `setColumnVisible(field, v)`, `toggleColumn(field)`, `showAll()`, `getVisibleColumns()`, `getHiddenColumns()` |
| PinnedColumnsPlugin | `pinnedColumns` | `setPinPosition(field, pos)`, `refreshStickyOffsets()`, `getLeftPinnedColumns()`, `getRightPinnedColumns()`, `clearStickyPositions()` |
| PinnedRowsPlugin | `pinnedRows` | `refresh()`, `addPanel(p)`, `removePanel(id)`, `addAggregationRow(c)`, `removeAggregationRow(id)` |
| ReorderPlugin | `reorderColumns` | `getColumnOrder()`, `moveColumn(field, toIndex)`, `setColumnOrder(order)`, `resetColumnOrder()` |
| RowDragDropPlugin | `rowDragDrop` | `moveRow(fromIndex, toIndex)`, `canMoveRow(fromIndex, toIndex)` |
| ColumnVirtualizationPlugin | `columnVirtualization` | `getIsVirtualized()`, `getVisibleColumnRange()`, `scrollToColumn(idx)`, `getTotalWidth()` |
| PrintPlugin | `print` | `isPrinting()`, `print()`, `print({ orientation, title, maxRows })` |
| UndoRedoPlugin | `undoRedo` | `undo()`, `redo()`, `canUndo()`, `canRedo()`, `clearHistory()`, `getUndoStack()`, `getRedoStack()`, `recordEdit(idx, field, old, new)`, `beginTransaction()`, `endTransaction()` |

Inter-plugin queries (`grid.query(name, ...)`) — used when one plugin reads
another without a hard dependency. SelectionPlugin exposes: `'getSelection'`,
`'selectRows'`, `'getSelectedRowIndices'`, `'getSelectedRows'`,
`'getSelectedColumns'`.

## Using Plugins (Advanced)

For building custom plugins or when you need to instantiate plugin classes yourself (e.g., to pass constructor-only options or extend `BaseGridPlugin`), use the plugin API directly. The result is identical to using features — this is just a different way to configure the same capabilities.

### Import Paths

The grid package provides multiple entry points for different use cases:

| Entry Point | What It Includes | Tree-Shaking |
| ----------- | ---------------- | ------------ |
| `@toolbox-web/grid` | Core grid only (auto-registers `<tbw-grid>`) | N/A |
| `@toolbox-web/grid/all` | Core + **all** plugins bundled | No |
| `@toolbox-web/grid/plugins/*` | Individual plugin (e.g., `/plugins/selection`) | Yes |

> **Important:** Do not import from both `@toolbox-web/grid` and `@toolbox-web/grid/all` in the same application. The `all` entry point already includes the core grid, so importing both will register the custom element twice.

#### Plugin Import Patterns

**For production apps using plugin API directly (best tree-shaking):**
```typescript
// Import core grid
import '@toolbox-web/grid';

// Import only the plugins you need
import { SelectionPlugin } from '@toolbox-web/grid/plugins/selection';
import { FilteringPlugin } from '@toolbox-web/grid/plugins/filtering';
import { EditingPlugin } from '@toolbox-web/grid/plugins/editing';
```

**For prototyping (includes core grid + all plugins):**
```typescript
// Import everything at once (includes core grid + all plugins)
import { SelectionPlugin, FilteringPlugin, EditingPlugin } from '@toolbox-web/grid/all';
```

### Registration

Pass plugin instances to the `gridConfig.plugins` array:

```typescript
import { queryGrid } from '@toolbox-web/grid';

const grid = queryGrid('tbw-grid');

grid.gridConfig = {
  columns: [...],
  plugins: [
    new SelectionPlugin({ mode: 'row' }),
    new FilteringPlugin({ debounceMs: 300 }),
  ],
};
```

## Plugin Configuration

Each plugin accepts a configuration object:

```typescript
// Selection plugin options
new SelectionPlugin({
  mode: 'row',
  multiSelect: true,
  checkbox: true,
});

// Filtering plugin options
new FilteringPlugin({
  debounceMs: 200,
  caseSensitive: false,
});

// Export plugin options
new ExportPlugin({
  fileName: 'grid-export',
  includeHeaders: true,
  onlyVisible: true,
});
```

## Creating Custom Plugins

The grid's plugin system lets you build fully custom functionality. Plugins extend [`BaseGridPlugin`](/grid/api/plugin-development/classes/basegridplugin.md) and can hook into lifecycle events, process rows/columns, handle keyboard events, and inject CSS.

For the full development guide including lifecycle hooks, plugin communication, the query system, and styling patterns, see [Writing Custom Plugins](/grid/plugin-development/custom-plugins.md).

## Known Incompatibilities

Some plugin combinations conflict and should not be used together. A development-mode warning is shown when conflicts are detected:

| Plugin A | Plugin B | Reason |
|----------|----------|--------|
| GroupingRowsPlugin | TreePlugin | Both transform the entire row model in different ways |
| GroupingRowsPlugin | PivotPlugin | Pivot creates its own aggregated row/column structure |
| TreePlugin | PivotPlugin | Pivot replaces the data structure; tree hierarchy cannot coexist |
| ServerSidePlugin | GroupingRowsPlugin | Grouping needs the full dataset; server-side loads blocks lazily |
| ServerSidePlugin | TreePlugin | Tree needs the full hierarchy; server-side cannot provide children on demand |
| ServerSidePlugin | PivotPlugin | Pivot needs the full dataset for aggregation |

## See Also

- [Common Patterns](/grid/guides/common-patterns.md) — Real-world recipes combining plugins (all frameworks)
- [Getting Started](/grid/getting-started.md) — Quick setup with features API
- [Custom Plugin Development](/grid/plugin-development/custom-plugins.md) — Build your own plugins
- [Architecture](/grid/architecture.md) — How the plugin system fits into the grid's internals
- [Performance Guide](/grid/guides/performance.md) — Bundle optimization with tree-shakeable features
