Skip to content

BaseGridPlugin

Abstract base class for all grid plugins.

new BaseGridPlugin(config: Partial<TConfig>)
PropertyTypeDescription
dependencies?PluginDependency[]Plugin dependencies - declare other plugins this one requires.
manifest?PluginManifest<any>Plugin manifest - declares owned properties, config rules, and hook priorities.
namestringUnique plugin identifier (derived from class name by default)
aliases?unknownAlternative names for backward compatibility. getPluginByName() matches against both name and aliases.
versionstringPlugin version - defaults to grid version for built-in plugins. Third-party plugins can override with their own semver.
styles?stringCSS styles to inject into the grid’s shadow DOM
cellRenderers?Record<string, CellRenderer>Custom cell renderers keyed by type name
headerRenderers?Record<string, HeaderRenderer>Custom header renderers keyed by type name
cellEditors?Record<string, CellEditor>Custom cell editors keyed by type name
gridGridElementThe grid instance this plugin is attached to
configTConfigPlugin configuration - merged with defaults in attach()
userConfigPartial<TConfig>User-provided configuration from constructor

Plugin dependencies - declare other plugins this one requires.

Dependencies are validated when the plugin is attached. Required dependencies throw an error if missing. Optional dependencies log an info message if missing.

static readonly dependencies: PluginDependency[] = [
{ name: 'editing', required: true, reason: 'Tracks cell edits for undo/redo' },
{ name: 'selection', required: false, reason: 'Enables selection-based undo' },
];

Plugin manifest - declares owned properties, config rules, and hook priorities.

This is read by the configuration validator to:

  • Validate that required plugins are loaded when their properties are used
  • Execute configRules to detect invalid/conflicting settings
  • Order hook execution based on priority
static override readonly manifest: PluginManifest<MyConfig> = {
ownedProperties: [
{ property: 'myProp', level: 'column', description: 'the "myProp" column property' },
],
configRules: [
{ id: 'myPlugin/conflict', severity: 'warn', message: '...', check: (c) => c.a && c.b },
],
};

Default configuration - subclasses should override this getter. Note: This must be a getter (not property initializer) for proper inheritance since property initializers run after parent constructor.

readonly defaultConfig: Partial<TConfig>

Get the current rows from the grid.

readonly rows: any[]

Get the original unfiltered/unprocessed rows from the grid. Use this when you need all source data regardless of active filters.

readonly sourceRows: any[]

Get the current columns from the grid.

readonly columns: ColumnConfig<any>[]

Get only visible columns from the grid (excludes hidden). Use this for rendering that needs to match the grid template.

readonly visibleColumns: ColumnConfig<any>[]

Get the grid as an HTMLElement for direct DOM operations. Use sparingly - prefer the typed GridElementRef API when possible.

readonly gridElement: HTMLElement
const width = this.gridElement.clientWidth;
this.gridElement.classList.add('my-plugin-active');

Get the disconnect signal for event listener cleanup. This signal is aborted when the grid disconnects from the DOM. Use this when adding event listeners that should be cleaned up automatically.

Best for:

  • Document/window-level listeners added in attach()
  • Listeners on the grid element itself
  • Any listener that should persist across renders

Not needed for:

  • Listeners on elements created in afterRender() (removed with element)
readonly disconnectSignal: AbortSignal
element.addEventListener('click', handler, { signal: this.disconnectSignal });
document.addEventListener('keydown', handler, { signal: this.disconnectSignal });

Get the grid-level icons configuration. Returns merged icons (user config + defaults).

readonly gridIcons: Required<GridIcons>

Check if animations are enabled at the grid level. Respects gridConfig.animation.mode and the CSS variable set by the grid.

Plugins should use this to skip animations when:

  • Animation mode is ‘off’ or false
  • User prefers reduced motion and mode is ‘reduced-motion’ (default)
readonly isAnimationEnabled: boolean
private get animationStyle(): 'slide' | 'fade' | false {
if (!this.isAnimationEnabled) return false;
return this.config.animation ?? 'slide';
}

Get the animation duration in milliseconds from CSS variable. Falls back to 200ms if not set.

Plugins can use this for their animation timing to stay consistent with the grid-level animation.duration setting.

readonly animationDuration: number
element.animate(keyframes, { duration: this.animationDuration });

Called when the plugin is attached to a grid. Override to set up event listeners, initialize state, etc.

attach(grid: GridElement): void
NameTypeDescription
gridGridElement
attach(grid: GridElement): void {
super.attach(grid);
// Set up document-level listeners with auto-cleanup
document.addEventListener('keydown', this.handleEscape, {
signal: this.disconnectSignal
});
}

Called when the plugin is detached from a grid. Override to clean up event listeners, timers, etc.

detach(): void
detach(): void {
// Clean up any state not handled by disconnectSignal
this.selectedRows.clear();
this.cache = null;
}

Called when another plugin is attached to the same grid. Use for inter-plugin coordination, e.g., to integrate with new plugins.

onPluginAttached(name: string, plugin: BaseGridPlugin): void
NameTypeDescription
namestringThe name of the plugin that was attached
pluginBaseGridPluginThe plugin instance (for direct access if needed)
onPluginAttached(name: string, plugin: BaseGridPlugin): void {
if (name === 'selection') {
// Integrate with selection plugin
this.selectionPlugin = plugin as SelectionPlugin;
}
}

Called when another plugin is detached from the same grid. Use to clean up inter-plugin references.

onPluginDetached(name: string): void
NameTypeDescription
namestringThe name of the plugin that was detached
onPluginDetached(name: string): void {
if (name === 'selection') {
this.selectionPlugin = undefined;
}
}

Get another plugin instance from the same grid. Use for inter-plugin communication.

Prefer grid.getPluginByName() when you don’t need the class import.

getPlugin(PluginClass: (args: any[]) => T): T | undefined
NameTypeDescription
PluginClass(args: any[]) => T
// Preferred: by name
const selection = this.grid?.getPluginByName('selection');
// Alternative: by class
const selection = this.getPlugin(SelectionPlugin);
if (selection) {
const selectedRows = selection.getSelectedRows();
}

Emit a custom event from the grid.

emit(eventName: string, detail: T): void
NameTypeDescription
eventNamestring
detailT

Emit a cancelable custom event from the grid.

emitCancelable(eventName: string, detail: T): boolean
NameTypeDescription
eventNamestring
detailT

boolean - true if the event was cancelled (preventDefault called), false otherwise


Subscribe to an event from another plugin. The subscription is automatically cleaned up when this plugin is detached.

on(eventType: string, callback: (detail: T) => void): void
NameTypeDescription
eventTypestringThe event type to listen for (e.g., ‘filter-change’)
callback(detail: T) => voidThe callback to invoke when the event is emitted
// In attach() or other initialization
this.on('filter-change', (detail) => {
console.log('Filter changed:', detail);
});

Unsubscribe from a plugin event.

off(eventType: string): void
NameTypeDescription
eventTypestringThe event type to stop listening for
this.off('filter-change');

Emit an event to other plugins via the Event Bus. This is for inter-plugin communication only; it does NOT dispatch DOM events. Use emit() to dispatch DOM events that external consumers can listen to.

emitPluginEvent(eventType: string, detail: T): void
NameTypeDescription
eventTypestringThe event type to emit (should be declared in manifest.events)
detailTThe event payload
// Emit to other plugins (not DOM)
this.emitPluginEvent('filter-change', { field: 'name', value: 'Alice' });
// For DOM events that consumers can addEventListener to:
this.emit('filter-change', { field: 'name', value: 'Alice' });

Request a re-render of the grid. Uses ROWS phase - does NOT trigger processColumns hooks.

requestRender(): void

Request a columns re-render of the grid. Uses COLUMNS phase - triggers processColumns hooks. Use this when your plugin needs to reprocess column configuration.

requestColumnsRender(): void

Request a re-render and restore focus styling afterward. Use this when a plugin action (like expand/collapse) triggers a render but needs to maintain keyboard navigation focus.

requestRenderWithFocus(): void

Request a lightweight style update without rebuilding DOM. Use this instead of requestRender() when only CSS classes need updating.

requestAfterRender(): void

Re-render visible rows without rebuilding the row model or recalculating geometry. Use this when row data has been updated in-place (e.g., server-side block loads) and only the visible viewport needs to re-render.

requestVirtualRefresh(): void

Resolve an icon value to string or HTMLElement. Checks plugin config first, then grid-level icons, then defaults.

resolveIcon(iconKey: unknown, pluginOverride: IconValue): IconValue
NameTypeDescription
iconKeyunknownThe icon key in GridIcons (e.g., ‘expand’, ‘collapse’)
pluginOverrideIconValueOptional plugin-level override

IconValue - The resolved icon value


Set an icon value on an element. Handles both string (text/HTML) and HTMLElement values.

setIcon(element: HTMLElement, icon: IconValue): void
NameTypeDescription
elementHTMLElementThe element to set the icon on
iconIconValueThe icon value (string or HTMLElement)

Log a warning with an optional diagnostic code.

When a diagnostic code is provided, the message is formatted with the code and a link to the troubleshooting docs.

warn(message: string): void
NameTypeDescription
messagestring
this.warn('Something went wrong'); // plain
this.warn(MISSING_BREAKPOINT, 'Set a breakpoint'); // with code + docs link

Throw an error with a diagnostic code and docs link. Use for configuration errors and API misuse that should halt execution.

throwDiagnostic(code: DiagnosticCode, message: string): never
NameTypeDescription
codeDiagnosticCode
messagestring

Transform rows before rendering. Called during each render cycle before rows are rendered to the DOM. Use this to filter, sort, or add computed properties to rows.

processRows(rows: unknown): any[]
NameTypeDescription
rowsunknownThe current rows array (readonly to encourage returning a new array)

any[] - The modified rows array to render

processRows(rows: readonly any[]): any[] {
// Filter out hidden rows
return rows.filter(row => !row._hidden);
}

Transform columns before rendering. Called during each render cycle before column headers and cells are rendered. Use this to add, remove, or modify column definitions.

processColumns(columns: unknown): ColumnConfig<any>[]
NameTypeDescription
columnsunknownThe current columns array (readonly to encourage returning a new array)

ColumnConfig<any>[] - The modified columns array to render

processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {
// Add a selection checkbox column
return [
{ field: '_select', header: '', width: 40 },
...columns
];
}

Called before each render cycle begins. Use this to prepare state or cache values needed during rendering.

Note: This hook is currently a placeholder for future implementation. It is defined in the interface but not yet invoked by the grid’s render pipeline. If you need this functionality, please open an issue or contribute an implementation.

beforeRender(): void
beforeRender(): void {
this.visibleRowCount = this.calculateVisibleRows();
}

Called after each render cycle completes. Use this for DOM manipulation, adding event listeners to rendered elements, or applying visual effects like selection highlights.

afterRender(): void
afterRender(): void {
// Apply selection styling to rendered rows
const rows = this.gridElement?.querySelectorAll('.data-row');
rows?.forEach((row, i) => {
row.classList.toggle('selected', this.selectedRows.has(i));
});
}

Called after each cell is rendered. This hook is more efficient than afterRender() for cell-level modifications because you receive the cell context directly - no DOM queries needed.

Use cases:

  • Adding selection/highlight classes to specific cells
  • Injecting badges or decorations
  • Applying conditional styling based on cell value

Performance note: Called for every visible cell during render. Keep implementation fast. This hook is also called during scroll when cells are recycled.

afterCellRender(context: AfterCellRenderContext): void
NameTypeDescription
contextAfterCellRenderContextThe cell render context with row, column, value, and elements
afterCellRender(context: AfterCellRenderContext): void {
// Add selection class without DOM queries
if (this.isSelected(context.rowIndex, context.colIndex)) {
context.cellElement.classList.add('selected');
}
// Add validation error styling
if (this.hasError(context.row, context.column.field)) {
context.cellElement.classList.add('has-error');
}
}

Called after a row is fully rendered (all cells complete). Use this for row-level decorations, styling, or ARIA attributes.

Common use cases:

  • Adding selection classes to entire rows (row-focus, selected)
  • Setting row-level ARIA attributes
  • Applying row validation highlighting
  • Tree indentation styling

Performance note: Called for every visible row during render. Keep implementation fast. This hook is also called during scroll when rows are recycled.

afterRowRender(context: AfterRowRenderContext): void
NameTypeDescription
contextAfterRowRenderContextThe row render context with row data and element
afterRowRender(context: AfterRowRenderContext): void {
// Add row selection class without DOM queries
if (this.isRowSelected(context.rowIndex)) {
context.rowElement.classList.add('selected', 'row-focus');
}
// Add validation error styling
if (this.rowHasErrors(context.row)) {
context.rowElement.classList.add('has-errors');
}
}

Called after scroll-triggered row rendering completes. This is a lightweight hook for applying visual state to recycled DOM elements. Use this instead of afterRender when you need to reapply styling during scroll.

Performance note: This is called frequently during scroll. Keep implementation fast.

onScrollRender(): void
onScrollRender(): void {
// Reapply selection state to visible cells
this.applySelectionToVisibleCells();
}

⚠️ Deprecated: Use getRowHeight instead. This hook will be removed in v2.0. The new getRowHeight(row, index) hook provides per-row height information which enables better position caching and variable row height support.

Return extra height contributed by this plugin (e.g., expanded detail rows). Used to adjust scrollbar height calculations for virtualization.

getExtraHeight(): number

number - Total extra height in pixels

// OLD (deprecated):
getExtraHeight(): number {
return this.expandedRows.size * this.detailHeight;
}
// NEW (preferred):
getRowHeight(row: unknown, index: number): number | undefined {
if (this.isExpanded(row)) {
return this.baseRowHeight + this.getDetailHeight(row);
}
return undefined;
}

⚠️ Deprecated: Use getRowHeight instead. This hook will be removed in v2.0. The new getRowHeight(row, index) hook provides per-row height information which enables better position caching and variable row height support.

Return extra height that appears before a given row index. Used by virtualization to correctly calculate scroll positions when there’s variable height content (like expanded detail rows) above the viewport.

getExtraHeightBefore(beforeRowIndex: number): number
NameTypeDescription
beforeRowIndexnumberThe row index to calculate extra height before

number - Extra height in pixels that appears before this row

// OLD (deprecated):
getExtraHeightBefore(beforeRowIndex: number): number {
let height = 0;
for (const expandedRowIndex of this.expandedRowIndices) {
if (expandedRowIndex < beforeRowIndex) {
height += this.getDetailHeight(expandedRowIndex);
}
}
return height;
}
// NEW (preferred):
getRowHeight(row: unknown, index: number): number | undefined {
if (this.isExpanded(row)) {
return this.baseRowHeight + this.getDetailHeight(row);
}
return undefined;
}

Get the height of a specific row. Used for synthetic rows (group headers, detail panels, etc.) that have fixed heights. Return undefined if this plugin does not manage the height for this row.

This hook is called during position cache rebuilds for variable row height virtualization. Plugins that create synthetic rows should implement this to provide accurate heights.

getRowHeight(row: unknown, index: number): number | undefined
NameTypeDescription
rowunknownThe row data
indexnumberThe row index in the processed rows array

number | undefined - The row height in pixels, or undefined if not managed by this plugin

getRowHeight(row: unknown, index: number): number | undefined {
// Group headers have a fixed height
if (this.isGroupHeader(row)) {
return 32;
}
return undefined; // Let grid use default/measured height
}

Adjust the virtualization start index to render additional rows before the visible range. Use this when expanded content (like detail rows) needs its parent row to remain rendered even when the parent row itself has scrolled above the viewport.

adjustVirtualStart(start: number, scrollTop: number, rowHeight: number): number
NameTypeDescription
startnumberThe calculated start row index
scrollTopnumberThe current scroll position
rowHeightnumberThe height of a single row

number - The adjusted start index (lower than or equal to original start)

adjustVirtualStart(start: number, scrollTop: number, rowHeight: number): number {
// If row 5 is expanded and scrolled partially, keep it rendered
for (const expandedRowIndex of this.expandedRowIndices) {
const expandedRowTop = expandedRowIndex * rowHeight;
const expandedRowBottom = expandedRowTop + rowHeight + this.detailHeight;
if (expandedRowBottom > scrollTop && expandedRowIndex < start) {
return expandedRowIndex;
}
}
return start;
}

Render a custom row, bypassing the default row rendering. Use this for special row types like group headers, detail rows, or footers.

renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void
NameTypeDescription
rowanyThe row data object
rowElHTMLElementThe row DOM element to render into
rowIndexnumberThe index of the row in the data array

boolean | void - true if the plugin handled rendering (prevents default), false/void for default rendering

renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void {
if (row._isGroupHeader) {
rowEl.innerHTML = `<div class="group-header">${row._groupLabel}</div>`;
return true; // Handled - skip default rendering
}
// Return void to let default rendering proceed
}

⚠️ Deprecated: Use handleQuery instead for new plugins. Will be removed in v2.

Handle queries from other plugins. This is the generic mechanism for inter-plugin communication. Plugins can respond to well-known query types or define their own.

Prefer handleQuery for new plugins - it has the same signature but a clearer name. onPluginQuery is kept for backwards compatibility.

onPluginQuery(query: PluginQuery): unknown
NameTypeDescription
queryPluginQueryThe query object with type and context

unknown - Query-specific response, or undefined if not handling this query

onPluginQuery(query: PluginQuery): unknown {
switch (query.type) {
case PLUGIN_QUERIES.CAN_MOVE_COLUMN:
// Prevent moving pinned columns
const column = query.context as ColumnConfig;
if (column.sticky === 'left' || column.sticky === 'right') {
return false;
}
break;
case PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS:
const params = query.context as ContextMenuParams;
return [{ id: 'my-action', label: 'My Action', action: () => {} }];
}
}

Handle queries from other plugins or the grid.

Queries are declared in manifest.queries and dispatched via grid.query(). This enables type-safe, discoverable inter-plugin communication.

handleQuery(query: PluginQuery): unknown
NameTypeDescription
queryPluginQueryThe query object with type and context

unknown - Query-specific response, or undefined if not handling this query

// In manifest
static override readonly manifest: PluginManifest = {
queries: [
{ type: 'canMoveColumn', description: 'Check if a column can be moved' },
],
};
// In plugin class
handleQuery(query: PluginQuery): unknown {
if (query.type === 'canMoveColumn') {
const column = query.context as ColumnConfig;
return !column.sticky; // Can't move sticky columns
}
}

Handle keyboard events on the grid. Called when a key is pressed while the grid or a cell has focus.

onKeyDown(event: KeyboardEvent): boolean | void
NameTypeDescription
eventKeyboardEventThe native KeyboardEvent

boolean | void - true to prevent default behavior and stop propagation, false/void to allow default

onKeyDown(event: KeyboardEvent): boolean | void {
// Handle Ctrl+A for select all
if (event.ctrlKey && event.key === 'a') {
this.selectAllRows();
return true; // Prevent default browser select-all
}
}

Handle cell click events. Called when a data cell is clicked (not headers).

onCellClick(event: CellClickEvent): boolean | void
NameTypeDescription
eventCellClickEventCell click event with row/column context

boolean | void - true to prevent default behavior and stop propagation, false/void to allow default

onCellClick(event: CellClickEvent): boolean | void {
if (event.field === '_select') {
this.toggleRowSelection(event.rowIndex);
return true; // Handled
}
}

Handle row click events. Called when any part of a data row is clicked. Note: This is called in addition to onCellClick, not instead of.

onRowClick(event: RowClickEvent): boolean | void
NameTypeDescription
eventRowClickEventRow click event with row context

boolean | void - true to prevent default behavior and stop propagation, false/void to allow default

onRowClick(event: RowClickEvent): boolean | void {
if (this.config.mode === 'row') {
this.selectRow(event.rowIndex, event.originalEvent);
return true;
}
}

Handle header click events. Called when a column header is clicked. Commonly used for sorting.

onHeaderClick(event: HeaderClickEvent): boolean | void
NameTypeDescription
eventHeaderClickEventHeader click event with column context

boolean | void - true to prevent default behavior and stop propagation, false/void to allow default

onHeaderClick(event: HeaderClickEvent): boolean | void {
if (event.column.sortable !== false) {
this.toggleSort(event.field);
return true;
}
}

Handle scroll events on the grid viewport. Called during scrolling. Note: This may be called frequently; debounce if needed.

onScroll(event: ScrollEvent): void
NameTypeDescription
eventScrollEventScroll event with scroll position and viewport dimensions
onScroll(event: ScrollEvent): void {
// Update sticky column positions
this.updateStickyPositions(event.scrollLeft);
}

Handle cell mousedown events. Used for initiating drag operations like range selection or column resize.

onCellMouseDown(event: CellMouseEvent): boolean | void
NameTypeDescription
eventCellMouseEventMouse event with cell context

boolean | void - true to indicate drag started (prevents text selection), false/void otherwise

onCellMouseDown(event: CellMouseEvent): boolean | void {
if (event.rowIndex !== undefined && this.config.mode === 'range') {
this.startDragSelection(event.rowIndex, event.colIndex);
return true; // Prevent text selection
}
}

Handle cell mousemove events during drag operations. Only called when a drag is in progress (after mousedown returned true).

onCellMouseMove(event: CellMouseEvent): boolean | void
NameTypeDescription
eventCellMouseEventMouse event with current cell context

boolean | void - true to continue handling the drag, false/void otherwise

onCellMouseMove(event: CellMouseEvent): boolean | void {
if (this.isDragging && event.rowIndex !== undefined) {
this.extendSelection(event.rowIndex, event.colIndex);
return true;
}
}

Handle cell mouseup events to end drag operations.

onCellMouseUp(event: CellMouseEvent): boolean | void
NameTypeDescription
eventCellMouseEventMouse event with final cell context

boolean | void - true if drag was finalized, false/void otherwise

onCellMouseUp(event: CellMouseEvent): boolean | void {
if (this.isDragging) {
this.finalizeDragSelection();
this.isDragging = false;
return true;
}
}

Contribute plugin-specific state for a column. Called by the grid when collecting column state for serialization. Plugins can add their own properties to the column state.

getColumnState(field: string): Partial<ColumnState> | undefined
NameTypeDescription
fieldstringThe field name of the column

Partial<ColumnState> | undefined - Partial column state with plugin-specific properties, or undefined if no state to contribute

getColumnState(field: string): Partial<ColumnState> | undefined {
const filterModel = this.filterModels.get(field);
if (filterModel) {
// Uses module augmentation to add filter property to ColumnState
return { filter: filterModel } as Partial<ColumnState>;
}
return undefined;
}

Apply plugin-specific state to a column. Called by the grid when restoring column state from serialized data. Plugins should restore their internal state based on the provided state.

applyColumnState(field: string, state: ColumnState): void
NameTypeDescription
fieldstringThe field name of the column
stateColumnStateThe column state to apply (may contain plugin-specific properties)
applyColumnState(field: string, state: ColumnState): void {
// Check for filter property added via module augmentation
const filter = (state as any).filter;
if (filter) {
this.filterModels.set(field, filter);
this.applyFilter();
}
}

Report horizontal scroll boundary offsets for this plugin. Plugins that obscure part of the scroll area (e.g., pinned/sticky columns) should return how much space they occupy on each side. The keyboard navigation uses this to ensure focused cells are fully visible.

getHorizontalScrollOffsets(rowEl: HTMLElement, focusedCell: HTMLElement): object | undefined
NameTypeDescription
rowElHTMLElementThe row element (optional, for calculating widths from rendered cells)
focusedCellHTMLElementThe currently focused cell element (optional, to determine if scrolling should be skipped)

object | undefined - Object with left/right pixel offsets and optional skipScroll flag, or undefined if plugin has no offsets

getHorizontalScrollOffsets(rowEl?: HTMLElement, focusedCell?: HTMLElement): { left: number; right: number; skipScroll?: boolean } | undefined {
// Calculate total width of left-pinned columns
const leftCells = rowEl?.querySelectorAll('.sticky-left') ?? [];
let left = 0;
leftCells.forEach(el => { left += (el as HTMLElement).offsetWidth; });
// Skip scroll if focused cell is pinned (always visible)
const skipScroll = focusedCell?.classList.contains('sticky-left');
return { left, right: 0, skipScroll };
}

Register a tool panel for this plugin. Return undefined if plugin has no tool panel. The shell will create a toolbar toggle button and render the panel content when the user opens the panel.

getToolPanel(): ToolPanelDefinition | undefined

ToolPanelDefinition | undefined - Tool panel definition, or undefined if plugin has no panel

getToolPanel(): ToolPanelDefinition | undefined {
return {
id: 'columns',
title: 'Columns',
icon: '',
tooltip: 'Show/hide columns',
order: 10,
render: (container) => {
this.renderColumnList(container);
return () => this.cleanup();
},
};
}

Register content for the shell header center section. Return undefined if plugin has no header content. Examples: search input, selection summary, status indicators.

getHeaderContent(): HeaderContentDefinition | undefined

HeaderContentDefinition | undefined - Header content definition, or undefined if plugin has no header content

getHeaderContent(): HeaderContentDefinition | undefined {
return {
id: 'quick-filter',
order: 10,
render: (container) => {
const input = document.createElement('input');
input.type = 'text';
input.placeholder = 'Search...';
input.addEventListener('input', this.handleInput);
container.appendChild(input);
return () => input.removeEventListener('input', this.handleInput);
},
};
}

AI assistants: For complete API documentation, implementation guides, and code examples for this library, see https://raw.githubusercontent.com/OysteinAmundsen/toolbox/main/llms-full.txt